aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe/icode/hipe_icode_mulret.erl
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/hipe/icode/hipe_icode_mulret.erl
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/hipe/icode/hipe_icode_mulret.erl')
-rw-r--r--lib/hipe/icode/hipe_icode_mulret.erl1323
1 files changed, 1323 insertions, 0 deletions
diff --git a/lib/hipe/icode/hipe_icode_mulret.erl b/lib/hipe/icode/hipe_icode_mulret.erl
new file mode 100644
index 0000000000..a6529c8519
--- /dev/null
+++ b/lib/hipe/icode/hipe_icode_mulret.erl
@@ -0,0 +1,1323 @@
+%% -*- erlang-indent-level: 2 -*-
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-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_icode_mulret.erl
+%% Author : Christoffer Vikstr�m <[email protected]>
+%% Purpose :
+%% Created : 23 Jun 2004 by Christoffer Vikstr�m <[email protected]>
+%%----------------------------------------------------------------------
+
+-module(hipe_icode_mulret).
+-export([mult_ret/4]).
+
+-include("../main/hipe.hrl").
+-include("hipe_icode.hrl").
+-include("hipe_icode_primops.hrl").
+
+%%>----------------------------------------------------------------------<
+%% Procedure : mult_ret/4
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+
+-spec mult_ret([_], atom(), comp_options(), _) -> [_].
+
+mult_ret(List, Mod, Opts, Exports) ->
+ case length(List) > 1 of
+ true ->
+ Table = analyse(List, Mod, Exports),
+ %% printTable(Mod, Exports, Table),
+ optimize(List, Mod, Opts, Table);
+ false ->
+ List
+ end.
+
+%%>-----------------------< Analysis Steps >-----------------------------<
+
+%%>----------------------------------------------------------------------<
+%% Procedure : analyse/3
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+analyse(List, _Mod, Exports) ->
+ MaxRets = hipe_rtl_arch:nr_of_return_regs(),
+ Table = mkTable(List),
+ %% printTable(Mod, Exports, Table),
+ Table2 = filterTable(Table, MaxRets, Exports),
+ %% printTable(Mod, Exports, Table2),
+ Table2.
+
+%%>----------------------------------------------------------------------<
+%% Procedure : mkTable/1
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+mkTable(List) ->
+ mkTable(List, {[], []}).
+
+mkTable([{MFA, Icode} | List], Table) ->
+ %% New Icode
+ {_LMin,LMax} = hipe_icode:icode_label_range(Icode),
+ hipe_gensym:set_label(icode, LMax+1),
+ {_VMin,VMax} = hipe_icode:icode_var_range(Icode),
+ hipe_gensym:set_var(icode, VMax+1),
+ case isFunDef(MFA) of
+ true ->
+ mkTable(List, Table);
+ false ->
+ CallList = mkCallList(MFA, Icode),
+ Optimizable = isOptimizable(Icode),
+ NewTable = addToTable(MFA, Optimizable, CallList, Table),
+ mkTable(List, NewTable)
+ end;
+mkTable([_|List], Table) -> mkTable(List, Table);
+mkTable([], Table) -> Table.
+
+%%>----------------------------------------------------------------------<
+%% Procedure : isFunDef/1
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+isFunDef({_, F, _}) ->
+ hd(atom_to_list(F)) =:= 45. %% 45 is the character '-'
+
+%%>----------------------------------------------------------------------<
+%% Procedure : mkCallList/1
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+mkCallList(MFA, Icode) ->
+ Code = hipe_icode:icode_code(Icode),
+ mkCallList(Code, MFA, []).
+
+mkCallList([#icode_call{'fun'=F, dstlist=Vars, type=local}|Code], MFA, Res) ->
+ {Size, DstList} = lookForDef(Code, Vars),
+ mkCallList(Code, MFA, [{callPair,MFA,{F,{matchSize,Size,DstList}}}|Res]);
+mkCallList([_|Code], MFA, Res) -> mkCallList(Code, MFA, Res);
+mkCallList([], _, Res) -> Res.
+
+%%>----------------------------------------------------------------------<
+%% Procedure : lookForDef/1
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+lookForDef([#icode_type{test={tuple,Size}, true_label=L}|Code], Vars) ->
+ Code2 = skipToLabel(Code, L),
+ DstLst = lookForUnElems(Code2, Vars),
+ case DstLst of
+ [] -> {1, Vars};
+ _ ->
+ DstLst2 = fixDstLst(DstLst, Size),
+ {Size, DstLst2}
+ end;
+lookForDef([#icode_move{src=Var, dst=NewVar}|Code], [Var]) ->
+ lookForDef(Code, [NewVar]);
+lookForDef([#icode_label{}|_], Vars) ->
+ {1, Vars};
+lookForDef([I|Code], [Var] = Vars) ->
+ Defs = hipe_icode:defines(I),
+ case lists:member(Var, Defs) of
+ true ->
+ {1, Vars};
+ false ->
+ lookForDef(Code, Vars)
+ end;
+lookForDef([], Vars) -> {1, Vars}.
+
+%%>----------------------------------------------------------------------<
+%% Procedure : skipToLabel/2
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+skipToLabel(Code, L) ->
+ case skipToLabel2(Code, L) of
+ noLabel ->
+ Code;
+ NewCode ->
+ NewCode
+ end.
+
+skipToLabel2([#icode_label{name = L}|Code],L) -> Code;
+skipToLabel2([_|Code], L) -> skipToLabel2(Code, L);
+skipToLabel2([], _) -> noLabel.
+
+%%>----------------------------------------------------------------------<
+%% Procedure : lookForUnElems/2
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+lookForUnElems(Code, Var) ->
+ lookForUnElems(Code, Var, []).
+
+lookForUnElems([#icode_call{'fun'=#unsafe_element{index=Nr}, args=Var,
+ dstlist=[Ret]}|Code], Var, Res) ->
+ lookForUnElems(Code, Var, [{Nr, Ret}|Res]);
+lookForUnElems([#icode_move{dst=Var}|_], [Var], Res) ->
+ lists:flatten(Res);
+lookForUnElems([#icode_call{dstlist=VarList}|_], VarList, Res) ->
+ lists:flatten(Res);
+lookForUnElems([_|Code], Var, Res) ->
+ lookForUnElems(Code, Var, Res);
+lookForUnElems([], _, Res) -> lists:flatten(Res).
+
+%%>----------------------------------------------------------------------<
+%% Procedure : fixDstLst/2
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+fixDstLst(DstLst, Size) when is_integer(Size) ->
+ fixDstLst(DstLst, Size, 1, []).
+
+fixDstLst(DstLst, Size, Cnt, Res) when Cnt =< Size ->
+ case isInLst(Cnt, DstLst) of
+ {true, Var} ->
+ fixDstLst(DstLst, Size, Cnt+1, [Var|Res]);
+ false ->
+ Var = hipe_icode:mk_var(hipe_gensym:new_var(icode)),
+ fixDstLst(DstLst, Size, Cnt+1, [Var|Res])
+ end;
+fixDstLst(_, Size, Cnt, Res) when Cnt > Size -> lists:reverse(Res).
+
+%%>----------------------------------------------------------------------<
+%% Procedure : isInLst/2
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+isInLst(Nr, [{Nr,Var}|_]) -> {true, Var};
+isInLst(Cnt, [_|DstLst]) -> isInLst(Cnt, DstLst);
+isInLst(_, []) -> false.
+
+%%>----------------------------------------------------------------------<
+%% Procedure : isOptimizable/1
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+isOptimizable(Icode) ->
+ %% Icode2 = hipe_icode:fixup_fallthroughs(Icode),
+ Icode2 = hipe_icode:strip_comments(Icode),
+ Cfg = hipe_icode_cfg:linear_to_cfg(Icode2),
+ %% hipe_icode_cfg:pp(Cfg),
+ case findReturnBlocks(Cfg) of
+ noReturn ->
+ {false, -1};
+ BlockList ->
+ processReturnBlocks(BlockList, Cfg)
+ end.
+
+%%>----------------------------------------------------------------------<
+%% Procedure : findReturnBlocks/2
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+findReturnBlocks(IcodeCfg) ->
+ Labels = hipe_icode_cfg:labels(IcodeCfg),
+ case searchBlocks(Labels, IcodeCfg) of
+ [] ->
+ noReturn;
+ BlockList->
+ BlockList
+ end.
+
+%%>----------------------------------------------------------------------<
+%% Procedure : searchBlocks/2
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+searchBlocks(Labels, IcodeCfg) ->
+ searchBlocks(Labels, IcodeCfg, []).
+
+searchBlocks([Label|Labels], IcodeCfg, Res) ->
+ Block = hipe_icode_cfg:bb(IcodeCfg, Label),
+ Code = hipe_bb:code(Block),
+ case searchBlockCode(Code) of
+ {hasReturn, RetVar} ->
+ searchBlocks(Labels, IcodeCfg, [{Label, RetVar}|Res]);
+ noReturn ->
+ searchBlocks(Labels, IcodeCfg, Res)
+ end;
+searchBlocks([], _, Res) -> Res.
+
+%%>----------------------------------------------------------------------<
+%% Procedure : searchBlockCode/1
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+searchBlockCode([#icode_return{vars=Vars}|_]) ->
+ {hasReturn, Vars};
+searchBlockCode([_|Icode]) ->
+ searchBlockCode(Icode);
+searchBlockCode([]) -> noReturn.
+
+%%>----------------------------------------------------------------------<
+%% Procedure : processReturnBlock/2
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+processReturnBlocks(Blocks, Cfg) ->
+ processReturnBlocks(Blocks, Cfg, {true, -1}, []).
+
+processReturnBlocks([{Label, Var}|BlockList], Cfg, {Opts, Size}, TypeLst) ->
+ {Opt, Type, Size2} = traverseCode(Label, Var, Cfg),
+ case (Size =:= -1) orelse (Size =:= Size2) of
+ true ->
+ processReturnBlocks(BlockList, Cfg,
+ {Opt andalso Opts, Size2}, [Type|TypeLst]);
+ false ->
+ {false, -1}
+ end;
+processReturnBlocks([], _, Res, TypeLst) ->
+ case lists:member(icode_var, TypeLst) of
+ true ->
+ {_, Size} = Res,
+ case Size > 1 of
+ true ->
+ Res;
+ false ->
+ {false, -1}
+ end;
+ false ->
+ {false, -1}
+ end.
+
+%%>----------------------------------------------------------------------<
+%% Procedure : traverseCode/3
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+traverseCode(Label, Var, Cfg) ->
+ traverseCode(Label, Var, Cfg, []).
+
+traverseCode(Label, Var, Cfg, LabLst) ->
+ Preds = hipe_icode_cfg:pred(Cfg, Label),
+ Block = hipe_icode_cfg:bb(Cfg, Label),
+ Code = hipe_bb:code(Block),
+ case findDefine(lists:reverse(Code), Var) of
+ {found, Type, NumRets} ->
+ {true, Type, NumRets};
+ {notFound, SrcVar} ->
+ case Preds of
+ [] ->
+ {false, none, -1};
+ [Pred] ->
+ case lists:member(Label, LabLst) of
+ false ->
+ traverseCode(Pred, SrcVar, Cfg, [Label|LabLst]);
+ true ->
+ {false, none, -1}
+ end;
+ _ ->
+ {false, none, -1}
+ end
+ end.
+
+%%>----------------------------------------------------------------------<
+%% Procedure : findDefine/2
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+findDefine([#icode_call{dstlist=Vars,'fun'=mktuple,args=Vs}|_], Vars) ->
+ case length(Vs) of
+ 1 ->
+ [{Type, _}] = Vs,
+ {found, Type, 1};
+ Len ->
+ case lists:any(fun hipe_icode:is_var/1, Vs) of
+ true ->
+ {found, icode_var, Len};
+ false ->
+ {found, icode_const, Len}
+ end
+ end;
+findDefine([#icode_move{dst=Var, src=Src}|Code], [Var]) ->
+ case hipe_icode:is_var(Src) of
+ true ->
+ findDefine(Code, [Src]);
+ false ->
+ case Src of
+ #icode_const{value={flat, Value}} ->
+ case is_tuple(Value) of
+ true ->
+ {found, icode_const, tuple_size(Value)};
+ false ->
+ {found, icode_const, 1}
+ end;
+ _ ->
+ findDefine(Code, [Var])
+ end
+ end;
+findDefine([_|Code], Var) ->
+ findDefine(Code, Var);
+findDefine([], Var) ->
+ {notFound, Var}.
+
+%%>----------------------------------------------------------------------<
+%% Procedure : addToTable/4
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+addToTable(MFA, Optimizable, CallList, {FunLst, CallLst}) ->
+ NewFunLst = [{MFA, Optimizable}|FunLst],
+ {NewFunLst, CallList ++ CallLst}.
+
+%%>----------------------------------------------------------------------<
+%% Procedure : filterTable/1
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+filterTable({FunLst, CallLst}, MaxRets, Exports) ->
+ filterTable(FunLst, CallLst, MaxRets, Exports, {[],[]}).
+
+filterTable([Fun|FunLst], CallLst, MaxRets, Exports, {Funs, Calls} = FCs) ->
+ {MFA, {ReturnOpt, Rets}} = Fun,
+ {CallOpt, CallsToKeep} = checkCalls(CallLst, MFA, Rets),
+ CallsToKeep2 = removeDuplicateCalls(CallsToKeep),
+ NotExported = checkExported(MFA, Exports),
+ case CallOpt andalso ReturnOpt andalso (Rets =< MaxRets) andalso
+ NotExported andalso (not containRecursiveCalls(CallsToKeep2, MFA)) of
+ true ->
+ filterTable(FunLst, CallLst, MaxRets, Exports,
+ {[Fun|Funs], CallsToKeep2 ++ Calls});
+ false ->
+ filterTable(FunLst, CallLst, MaxRets, Exports, FCs)
+ end;
+filterTable([], _, _, _, Res) -> Res.
+
+removeDuplicateCalls(Calls) ->
+ removeDuplicateCalls(Calls, []).
+
+removeDuplicateCalls([Call|CallsToKeep], Res) ->
+ case lists:member(Call, CallsToKeep) of
+ true ->
+ removeDuplicateCalls(CallsToKeep, Res);
+ false ->
+ removeDuplicateCalls(CallsToKeep, [Call|Res])
+ end;
+removeDuplicateCalls([], Res) -> lists:reverse(Res).
+
+containRecursiveCalls([Call|Calls], Fun) ->
+ {callPair, Caller, {Callee, _}} = Call,
+ case (Callee =:= Fun) andalso (Caller =:= Fun) of
+ true ->
+ true;
+ false->
+ containRecursiveCalls(Calls, Fun)
+ end;
+containRecursiveCalls([], _) -> false.
+
+%%>----------------------------------------------------------------------<
+%% Procedure : checkCalls/3
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+checkCalls(CallLst, MFA, Rets) ->
+ checkCalls(CallLst, MFA, Rets, [], []).
+
+checkCalls([C = {callPair, _, {MFA, {matchSize, Rets, _}}}|CallLst],
+ MFA, Rets, Res, Opt) ->
+ checkCalls(CallLst, MFA, Rets, [C|Res], [true|Opt]);
+checkCalls([{callPair, _, {MFA, {matchSize, _, _}}}|CallLst],
+ MFA, Rets, Res, Opt) ->
+ checkCalls(CallLst, MFA, Rets, Res, [false|Opt]);
+checkCalls([_|CallLst], MFA, Rets, Res, Opt) ->
+ checkCalls(CallLst, MFA, Rets, Res, Opt);
+checkCalls([], _, _, Res, Opt) -> {combineOpts(Opt), Res}.
+
+%%>----------------------------------------------------------------------<
+%% Procedure : combineOpts/1
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+combineOpts([]) -> false;
+combineOpts([Opt]) -> Opt;
+combineOpts([Opt|Opts]) -> Opt andalso combineOpts(Opts).
+
+%%>----------------------------------------------------------------------<
+%% Procedure : checkCalls/2
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+checkExported({_,F,A}, [{F,A}|_]) -> false;
+checkExported(MFA, [_|Exports]) -> checkExported(MFA, Exports);
+checkExported(_, []) -> true.
+
+%%>----------------------< Optimization Steps >--------------------------<
+
+%%>----------------------------------------------------------------------<
+%% Procedure : optimize/4
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+optimize(List, _Mod, Opts, Table) ->
+ {FunLst, CallLst} = Table,
+ List2 = optimizeFuns(FunLst, Opts, List),
+ optimizeCalls(CallLst, Opts, List2).
+
+%%>----------------------------------------------------------------------<
+%% Procedure : optimizeFuns/3
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+optimizeFuns([{Fun, _}|FunList], Opts, List) ->
+ NewList = findFun(List, Fun),
+ optimizeFuns(FunList, Opts, NewList);
+optimizeFuns([],_,List) -> List.
+
+findFun(List, Fun) -> findFun(List, Fun, []).
+findFun([{Fun, Icode}|List], Fun, Res) ->
+ NewIcode = optimizeFun(Icode),
+ findFun(List, Fun, [{Fun, NewIcode}|Res]);
+findFun([I|List], Fun, Res) -> findFun(List, Fun, [I|Res]);
+findFun([], _, Res) -> lists:reverse(Res).
+
+
+optimizeFun(Icode) ->
+ {_LMin,LMax} = hipe_icode:icode_label_range(Icode),
+ hipe_gensym:set_label(icode, LMax+1),
+ {_VMin,VMax} = hipe_icode:icode_var_range(Icode),
+ hipe_gensym:set_var(icode, VMax+1),
+ %% Icode2 = hipe_icode:fixup_fallthroughs(Icode),
+ Icode2 = hipe_icode:strip_comments(Icode),
+ Cfg = hipe_icode_cfg:linear_to_cfg(Icode2),
+ case findReturnBlocks(Cfg) of
+ noReturn ->
+ false;
+ BlockList ->
+ NewCfg = optimizeReturnBlocks(BlockList, Cfg),
+ hipe_icode_cfg:cfg_to_linear(NewCfg)
+ end.
+
+optimizeReturnBlocks([Block|BlockList], Cfg) ->
+ {NewCfg, Vars} = optimizeReturnBlock(Block, Cfg),
+ NewCfg2 = case Vars of
+ [_] ->
+ Cfg;
+ _ ->
+ {Label, _} = Block,
+ updateReturnBlock(Label, Vars, NewCfg)
+ end,
+ optimizeReturnBlocks(BlockList, NewCfg2);
+optimizeReturnBlocks([], Cfg) -> Cfg.
+
+optimizeReturnBlock(Block, Cfg) ->
+ optimizeReturnBlock(Block, Cfg, []).
+
+optimizeReturnBlock({Label,Var}, Cfg, UpdateMap) ->
+ Preds = hipe_icode_cfg:pred(Cfg, Label),
+ Block = hipe_icode_cfg:bb(Cfg, Label),
+ Code = hipe_bb:code(Block),
+ case optimizeDefine(Code, Var) of
+ {found, NewBlockCode, Vars} ->
+ NewBlock = hipe_bb:code_update(Block, NewBlockCode),
+ NewCfg = resolveUpdateMap(UpdateMap, Cfg),
+ {hipe_icode_cfg:bb_add(NewCfg, Label, NewBlock), Vars};
+ {none, NewBlockCode, NewVar} ->
+ case Preds of
+ [Pred] ->
+ NewBlock = hipe_bb:code_update(Block, NewBlockCode),
+ optimizeReturnBlock({Pred,NewVar}, Cfg,
+ [{Label, NewBlock}|UpdateMap]);
+ [_|_] ->
+ {Cfg, Var}
+ end;
+ {none, noOpt} ->
+ {Cfg, Var}
+ end.
+
+optimizeDefine(Code, Dst) ->
+ optimizeDefine(lists:reverse(Code), Dst, [], []).
+
+optimizeDefine([I|Code], Dsts, DstLst, Res) ->
+ [Ds] = Dsts,
+ case isCallPrimop(I, mktuple) andalso DstLst =:= [] of
+ true ->
+ case (hipe_icode:call_dstlist(I) =:= Dsts) of
+ true ->
+ case (hipe_icode:call_args(I) > 1) of
+ true ->
+ optimizeDefine(Code, Dsts, hipe_icode:call_args(I), Res);
+ false ->
+ {none, noOpt}
+ end;
+ false ->
+ optimizeDefine(Code, Dsts, DstLst, [I|Res])
+ end;
+ false ->
+ case hipe_icode:is_move(I) andalso DstLst =:= [] of
+ true ->
+ case hipe_icode:move_dst(I) =:= Ds of
+ true ->
+ Src = hipe_icode:move_src(I),
+ case hipe_icode:is_var(Src) of
+ true ->
+ NewDst = hipe_icode:move_src(I),
+ optimizeDefine(Code, [NewDst], DstLst, Res);
+ false ->
+ case Src of
+ #icode_const{value={flat, T}} when is_tuple(T) ->
+ NewLst = tuple_to_list(T),
+ optimizeDefine(Code, Dsts, NewLst, Res);
+ _ ->
+ {none, noOpt}
+ end
+ end;
+ false ->
+ optimizeDefine(Code, Dsts, DstLst, [I|Res])
+ end;
+ false ->
+ case lists:member(Ds, hipe_icode:defines(I)) andalso DstLst =:= [] of
+ true ->
+ {none, noOpt};
+ false ->
+ optimizeDefine(Code, Dsts, DstLst, [I|Res])
+ end
+ end
+ end;
+optimizeDefine([], Dsts, DstLst, Res) ->
+ case DstLst of
+ [] ->
+ {none, Res, Dsts};
+ _ ->
+ {found, Res, DstLst}
+ end.
+
+resolveUpdateMap([{Label, Block}|UpdateMap], Cfg) ->
+ resolveUpdateMap(UpdateMap, hipe_icode_cfg:bb_add(Cfg, Label, Block));
+resolveUpdateMap([], Cfg) -> Cfg.
+
+%%>----------------------------------------------------------------------<
+%% Procedure : updateReturnBlock/3
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+updateReturnBlock(Label, Vars, IcodeCfg) ->
+ Block = hipe_icode_cfg:bb(IcodeCfg, Label),
+ Code = hipe_bb:code(Block),
+ NewCode = updateReturnCode(Code, Vars),
+ NewBlock = hipe_bb:code_update(Block, NewCode),
+ hipe_icode_cfg:bb_add(IcodeCfg, Label, NewBlock).
+
+updateReturnCode(Code, DstLst) ->
+ updateReturnCode(Code, DstLst, []).
+
+updateReturnCode([I| Code], DstLst, Res) ->
+ case hipe_icode:is_return(I) of
+ true ->
+ updateReturnCode(Code, DstLst, [hipe_icode:mk_return(DstLst)|Res]);
+ false ->
+ updateReturnCode(Code, DstLst, [I|Res])
+ end;
+updateReturnCode([], _, Res) -> lists:reverse(Res).
+
+%%>----------------------------------------------------------------------<
+%% Procedure : optimizeCalls/3
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+optimizeCalls([Call|CallLst], _Opts, List) ->
+ {callPair, Caller, {Callee, {matchSize, _, DstLst}}} = Call,
+ NewList = optimizeCall(List, Caller, Callee, DstLst),
+ optimizeCalls(CallLst, _Opts, NewList);
+optimizeCalls([], _Opts, List) -> List.
+
+%%>----------------------------------------------------------------------<
+%% Procedure : optimizeCall/4
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+optimizeCall(List, Caller, Callee, DstLst) ->
+ optimizeCall(List, Caller, Callee, DstLst, []).
+
+optimizeCall([{MFA, Icode}|List], MFA, Callee, DstLst, Res) ->
+ {_LMin,LMax} = hipe_icode:icode_label_range(Icode),
+ hipe_gensym:set_label(icode, LMax+1),
+ {_VMin,VMax} = hipe_icode:icode_var_range(Icode),
+ hipe_gensym:set_var(icode, VMax+1),
+ %% Icode2 = hipe_icode:fixup_fallthroughs(Icode),
+ Icode2 = hipe_icode:strip_comments(Icode),
+ Cfg = hipe_icode_cfg:linear_to_cfg(Icode2),
+ NewIcode = findAndUpdateCalls(Cfg, Callee, DstLst),
+ optimizeCall(List, MFA, Callee, DstLst, [{MFA, NewIcode}|Res]);
+optimizeCall([I|List], Caller, Callee, DstLst, Res) ->
+ optimizeCall(List, Caller, Callee, DstLst, [I|Res]);
+optimizeCall([], _, _, _, Res) -> lists:reverse(Res).
+
+%%>----------------------------------------------------------------------<
+%% Procedure : findAndUpdateCall/3
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+findAndUpdateCalls(Cfg, Callee, DstLst) ->
+ Labels = hipe_icode_cfg:labels(Cfg),
+ Cfg2 = findAndUpdateCalls(Cfg, Labels, Callee, DstLst, []),
+ hipe_icode_cfg:cfg_to_linear(Cfg2).
+findAndUpdateCalls(Cfg, [L|Labels], Callee, DstLst, Visited) ->
+ %% Block = hipe_icode_cfg:bb(Cfg, L),
+ %% Code = hipe_bb:code(Block),
+ case containCorrectCall(Cfg, L, Callee, DstLst) of
+ true ->
+ Block = hipe_icode_cfg:bb(Cfg,L),
+ Code = hipe_bb:code(Block),
+ {NewCode, OldVar} = updateCode(Code, Callee, DstLst),
+ NewBlock = hipe_bb:code_update(Block, NewCode),
+ Cfg2 = hipe_icode_cfg:bb_add(Cfg, L, NewBlock),
+ Cfg3 = cleanUpAffectedCode(Cfg2, OldVar, Callee, L, Visited),
+ findAndUpdateCalls(Cfg3, Labels, Callee, DstLst, [L|Visited]);
+ false ->
+ findAndUpdateCalls(Cfg, Labels, Callee, DstLst, [L|Visited])
+ end;
+findAndUpdateCalls(Cfg,[], _, _, _) -> Cfg.
+
+containCorrectCall(Cfg, Label, Callee, DstLst) ->
+ Block = hipe_icode_cfg:bb(Cfg,Label),
+ Code = hipe_bb:code(Block),
+ case containCallee(Code, Callee) of
+ {true, OldVar} ->
+ Succs = hipe_icode_cfg:succ(Cfg, Label),
+ checkForUnElems(Succs, OldVar, DstLst, Cfg);
+ false ->
+ false
+ end.
+
+checkForUnElems([], _, _, _) -> false;
+checkForUnElems([Succ|Succs], OldVar, DstLst, Cfg) ->
+ Block = hipe_icode_cfg:bb(Cfg,Succ),
+ Code = hipe_bb:code(Block),
+ case checkForUnElems2(Code, OldVar, DstLst, []) of
+ true ->
+ true;
+ false ->
+ checkForUnElems(Succs, OldVar, DstLst, Cfg)
+ end.
+
+checkForUnElems2([I|Code], OldVar, DstLst, DstRes) ->
+ case isCallPrimop(I, unsafe_element) of
+ true ->
+ case (hipe_icode:call_args(I) =:= OldVar) of
+ true ->
+ [Dst] = hipe_icode:call_dstlist(I),
+ case lists:member(Dst, DstLst) of
+ true ->
+ checkForUnElems2(Code, OldVar, DstLst, [Dst|DstRes]);
+ false ->
+ checkForUnElems2(Code, OldVar, DstLst, DstRes)
+ end;
+ false ->
+ checkForUnElems2(Code, OldVar, DstLst, DstRes)
+ end;
+ false ->
+ checkForUnElems2(Code, OldVar, DstLst, DstRes)
+ end;
+checkForUnElems2([], _, DstLst, DstRes) -> DstLst =:= lists:reverse(DstRes).
+
+
+containCallee([I|Code], Callee) ->
+ case isCallLocal(I, Callee) of
+ true ->
+ {true, hipe_icode:call_dstlist(I)};
+ false ->
+ containCallee(Code, Callee)
+ end;
+containCallee([], _) -> false.
+
+
+updateCode(Code, Callee, DstLst) ->
+ updateCode(Code, Callee, DstLst, [], []).
+
+updateCode([I|Code], Callee, DstLst, Res, OldVars) ->
+ case isCallLocal(I, Callee) of
+ true ->
+ Vars = hipe_icode:call_dstlist(I),
+ I2 = hipe_icode:call_dstlist_update(I, DstLst),
+ updateCode(Code, Callee, DstLst, [I2|Res], Vars);
+ false ->
+ updateCode(Code, Callee, DstLst, [I|Res], OldVars)
+ end;
+updateCode([], _, _, Res, OldVars) -> {lists:reverse(Res), OldVars}.
+
+
+cleanUpAffectedCode(Cfg, OldVar, Callee, Label, Visited) ->
+ Block = hipe_icode_cfg:bb(Cfg,Label),
+ Code = hipe_bb:code(Block),
+ {CodeBefore, CodeAfter, DstLst} = divideAtCall(Code, Callee),
+ {NewCodeAfter, ContLab, FailLab} = findType(CodeAfter, OldVar),
+ ContBlock = hipe_icode_cfg:bb(Cfg, ContLab),
+ Succs = hipe_icode_cfg:succ(Cfg, ContLab),
+ ContCode = hipe_bb:code(ContBlock),
+ {NewContCode, NewFailLab} = removeUnElems(ContCode, OldVar, DstLst),
+ NewBlock = hipe_bb:code_update(Block,
+ CodeBefore ++ NewCodeAfter ++ NewContCode),
+ Cfg2 = hipe_icode_cfg:bb_add(Cfg, Label, NewBlock),
+ Cfg3 = resolveSuccBlocks(Succs, OldVar, DstLst, [Label|Visited],
+ NewFailLab, Cfg2),
+ insertMiddleFailBlock(Cfg3, NewFailLab, FailLab, OldVar, DstLst).
+
+divideAtCall(Code, Caller) ->
+ divideAtCall(Code, Caller, []).
+
+divideAtCall([I|Code], Caller, Tail) ->
+ case isCallLocal(I, Caller) of
+ true ->
+ {lists:reverse([I|Tail]), Code, hipe_icode:call_dstlist(I)};
+ false ->
+ divideAtCall(Code, Caller, [I|Tail])
+ end;
+divideAtCall([], _, Tail) -> {Tail, []}.
+
+findType(CodeAfter, OldVar) ->
+ findType(CodeAfter, OldVar, [], {none, none}).
+
+findType([I|Code], OldVar, Rest, Succs) ->
+ case hipe_icode:is_type(I) of
+ true ->
+ case hipe_icode:type_args(I) =:= OldVar of
+ true ->
+ TrueLab = hipe_icode:type_true_label(I),
+ FalseLab = hipe_icode:type_false_label(I),
+ findType(Code, OldVar, Rest, {TrueLab, FalseLab});
+ false ->
+ findType(Code, OldVar, [I|Rest], Succs)
+ end;
+ false ->
+ case hipe_icode:is_move(I) of
+ true ->
+ case [hipe_icode:move_src(I)] =:= OldVar of
+ true ->
+ findType(Code, hipe_icode:move_dst(I), [I|Rest], Succs);
+ false ->
+ findType(Code, OldVar, [I|Rest], Succs)
+ end;
+ false ->
+ findType(Code, OldVar, [I|Rest], Succs)
+ end
+ end;
+findType([],_,Rest, {TrueLab, FalseLab}) ->
+ {lists:reverse(Rest), TrueLab, FalseLab}.
+
+%% Nesting hell... check for redundancies.
+%% ---------------------------------------
+removeUnElems(Code, OldVars, DstLst) ->
+ removeUnElems(Code, OldVars, DstLst, [], false, none).
+
+removeUnElems([I|Code], [OldVar] = OldVars, DstLst, Res, Def, Lab) ->
+ case isCallPrimop(I, unsafe_element) of
+ true ->
+ case (hipe_icode:call_args(I) =:= OldVars) of
+ true ->
+ removeUnElems(Code, OldVars, DstLst, Res, Def, Lab);
+ false ->
+ case lists:member(OldVar, hipe_icode:call_args(I)) of
+ true ->
+ %% XXX: the following test seems redundant,
+ %% hence commented out -- KOSTIS
+ %% case Def of
+ %% true ->
+ removeUnElems(Code, OldVars, DstLst, [I|Res], Def, Lab);
+ %% false ->
+ %% removeUnElems(Code, OldVars, DstLst,
+ %% [I|Res], Def, Lab)
+ %% end;
+ false ->
+ io:format("Borde aldrig kunna hamna h�r!", []),
+ removeUnElems(Code, OldVars, DstLst, [I|Res], Def, Lab)
+ end
+ end;
+ false ->
+ case hipe_icode:is_move(I) of
+ true ->
+ case hipe_icode:move_src(I) =:= OldVar of
+ true ->
+ NewVar = hipe_icode:move_dst(I),
+ removeUnElems(Code, [NewVar], DstLst, [I|Res], Def, Lab);
+ false ->
+ removeUnElems(Code, OldVars, DstLst, [I|Res], Def, Lab)
+ end;
+ false ->
+ case hipe_icode:is_type(I) andalso not Def of
+ true ->
+ NewFalseLab = case Lab =:= none of
+ true ->
+ hipe_gensym:get_next_label(icode);
+ false ->
+ Lab
+ end,
+ _I2 = updateTypeFalseLabel(I, NewFalseLab),
+ removeUnElems(Code, OldVars, DstLst, [I|Res], Def, NewFalseLab);
+ false ->
+ case lists:member(OldVar, hipe_icode:uses(I)) andalso Def of
+ true ->
+ removeUnElems(Code, OldVars, DstLst, [I|Res], Def, Lab);
+ false ->
+ case lists:member(OldVar, hipe_icode:defines(I)) of
+ true ->
+ removeUnElems(Code, OldVars, DstLst, [I|Res], true, Lab);
+ false ->
+ removeUnElems(Code, OldVars, DstLst, [I|Res], Def, Lab)
+ end
+ end
+ end
+ end
+ end;
+removeUnElems([], _, _, Res,_, Lab) -> {lists:reverse(Res), Lab}.
+
+
+updateTypeFalseLabel(Instr, NewFalseLabel) ->
+ TrueLabel = hipe_icode:type_true_label(Instr),
+ Args = hipe_icode:type_args(Instr),
+ Type = hipe_icode:type_test(Instr),
+ hipe_icode:mk_type(Args, Type, TrueLabel, NewFalseLabel).
+
+
+resolveSuccBlocks(Succs, OldVar, DstLst, Visited, FailLab, Cfg) ->
+ NewSuccs = [X || X <- Succs, not lists:member(X, Visited)],
+ resolveSuccBlocks2(NewSuccs, OldVar, DstLst, Visited, FailLab, Cfg).
+
+resolveSuccBlocks2([Succ|Succs], OldVar, DstLst, Vis, FailLab, Cfg) ->
+ Block = hipe_icode_cfg:bb(Cfg,Succ),
+ Code = hipe_bb:code(Block),
+ {NewCode, ReDefined} = checkUsesDefs(Code, OldVar, DstLst, FailLab),
+ NewBlock = hipe_bb:code_update(Block, NewCode),
+ Cfg2 = hipe_icode_cfg:bb_add(Cfg, Succ, NewBlock),
+ case ReDefined of
+ true ->
+ resolveSuccBlocks2(Succs, OldVar, DstLst, [Succ|Vis], FailLab, Cfg2);
+ false ->
+ NewSuccs = hipe_icode_cfg:succ(Cfg, Succ),
+ NewSuccs2 = [X || X <- NewSuccs, not lists:member(X, Vis++Succs)],
+ resolveSuccBlocks2(NewSuccs2++Succs, OldVar, DstLst,
+ [Succ|Vis], FailLab, Cfg2)
+ end;
+resolveSuccBlocks2([], _, _, _, _, Cfg) -> Cfg.
+
+
+checkUsesDefs(Code, OldVar, DstLst, FailLab) ->
+ checkUsesDefs(Code, OldVar, DstLst, FailLab, [], false).
+
+checkUsesDefs([I|Code], OldVar, DstLst, FailLab, Res, Defined) ->
+ [OVar] = OldVar,
+ case hipe_icode:is_move(I) of
+ true ->
+ case hipe_icode:move_src(I) =:= OVar of
+ true ->
+ NewVar = hipe_icode:move_dst(I),
+ checkUsesDefs(Code, NewVar, DstLst, FailLab, [I|Res], true);
+ false ->
+ case lists:member(OVar, hipe_icode:defines(I)) of
+ true ->
+ checkUsesDefs(Code, OldVar, DstLst, FailLab, [I|Res], true);
+ false ->
+ checkUsesDefs(Code, OldVar, DstLst, FailLab, [I|Res], Defined)
+ end
+ end;
+ false ->
+ case hipe_icode:is_type(I) andalso not Defined of
+ true ->
+ case FailLab =/= none of
+ true ->
+ _I2 = updateTypeFalseLabel(I, FailLab),
+ checkUsesDefs(Code, OldVar, DstLst, FailLab, [I|Res], Defined);
+ false ->
+ checkUsesDefs(Code, OldVar, DstLst, FailLab, [I|Res], Defined)
+ end;
+ false ->
+ case (lists:member(OVar, hipe_icode:uses(I))) andalso
+ (not Defined) andalso (FailLab =/= none) of
+ true ->
+ Tpl = hipe_icode:mk_primop(OldVar, mktuple, DstLst),
+ checkUsesDefs(Code, OldVar, DstLst, FailLab, [I,Tpl|Res], true);
+ false ->
+ case lists:member(OVar, hipe_icode:defines(I)) of
+ true ->
+ checkUsesDefs(Code, OldVar, DstLst, FailLab, [I|Res], true);
+ false ->
+ checkUsesDefs(Code, OldVar, DstLst, FailLab, [I|Res],Defined)
+ end
+ end
+ end
+ end;
+checkUsesDefs([], _, _, _, Res, Defined) -> {lists:reverse(Res), Defined}.
+
+
+insertMiddleFailBlock(Cfg, NewFailLabel, OldFailLabel, OldVar, DstLst) ->
+ case NewFailLabel =:= none of
+ true ->
+ Cfg;
+ false ->
+ NewCode = [hipe_icode:mk_primop(OldVar, mktuple, DstLst),
+ hipe_icode:mk_goto(OldFailLabel)],
+ NewBlock = hipe_bb:mk_bb(NewCode),
+ hipe_icode_cfg:bb_add(Cfg, NewFailLabel, NewBlock)
+ end.
+
+
+isCallLocal(Instr, Fun) ->
+ hipe_icode:is_call(Instr) andalso (hipe_icode:call_type(Instr) =:= local)
+ andalso (hipe_icode:call_fun(Instr) =:= Fun).
+
+isCallPrimop(Instr, Fun) ->
+ case hipe_icode:is_call(Instr) of
+ true ->
+ case is_tuple(hipe_icode:call_fun(Instr)) of
+ true ->
+ ((hipe_icode:call_type(Instr) =:= primop) andalso
+ (element(1,hipe_icode:call_fun(Instr)) =:= Fun));
+ false ->
+ ((hipe_icode:call_type(Instr) =:= primop) andalso
+ (hipe_icode:call_fun(Instr) =:= Fun))
+ end;
+ false ->
+ false
+ end.
+
+
+%% >-------------------------< Debug code >------------------------------<
+
+-ifdef(DEBUG_MULRET).
+
+%%>----------------------------------------------------------------------<
+%% Procedure : printTable/1
+%% Purpose :
+%% Arguments :
+%% Return :
+%% Notes :
+%%>----------------------------------------------------------------------<
+printTable(Mod, Exports, {FunLst, CallLst}) ->
+ {Y,Mo,D} = date(),
+ {H,Mi,S} = time(),
+ io:format("Module: ~w - (~w/~w-~w, ~w:~w:~w)~n=======~n",
+ [Mod,D,Mo,Y,H,Mi,S]),
+ io:format("Exports: ~w~n", [Exports]),
+ io:format("FunList: ~n"),
+ printFunList(FunLst),
+ io:format("CallList: ~n"),
+ printCallList(CallLst).
+
+printFunList([Fun|FunLst]) ->
+ io:format(" ~w~n", [Fun]),
+ printFunList(FunLst);
+printFunList([]) -> io:format("~n").
+
+printCallList([Call|CallLst]) ->
+ io:format(" ~w~n", [Call]),
+ printCallList(CallLst);
+printCallList([]) -> io:format("~n").
+
+-endif.
+
+%% >----------------------------< Old code >--------------------------------<
+
+%% %%>----------------------------------------------------------------------<
+%% % Procedure : findCallCode/3
+%% % Purpose :
+%% % Arguments :
+%% % Return :
+%% % Notes :
+%% %%>----------------------------------------------------------------------<
+%% findCallCode(List, Callee, DstLst) -> findCallCode(List, Callee, DstLst, []).
+%% findCallCode([I=#icode_call{'fun'=Callee, dstlist=Var, type=local}, I2, I3|List],
+%% Callee, DstLst, Res) ->
+%% NewList = removeUnElems(List, Var),
+%% %% _Uses = checkForUses(NewList, Var, DstLst),
+%% Size = length(DstLst),
+%% case I2 of
+%% #icode_type{test={tuple, Size}, args=Var, true_label=Label} ->
+%% case I3 of
+%% #icode_label{name=Label} ->
+%% findCallCode(NewList, Callee, DstLst,
+%% [I#icode_call{dstlist=DstLst}|Res]);
+%% _ ->
+%% findCallCode(NewList, Callee, DstLst,
+%% [#goto{label=Label},
+%% I#icode_call{dstlist=DstLst}|Res])
+%% end;
+%% _ ->
+%% findCallCode(NewList, Callee, DstLst,
+%% [I2,I#icode_call{dstlist=DstLst}|Res])
+%% end;
+%% findCallCode([I|List], Callee, DstLst, Res) ->
+%% findCallCode(List, Callee, DstLst, [I|Res]);
+%% findCallCode([], _, _, Res) -> lists:reverse(Res).
+
+
+%% %%>----------------------------------------------------------------------<
+%% % Procedure : checkForUses
+%% % Purpose :
+%% % Arguments :
+%% % Return :
+%% % Notes :
+%% %%>----------------------------------------------------------------------<
+%% checkForUses(List, Var, Dsts) -> checkForUses(List, Var, Dsts, [], List).
+%% checkForUses([I|List], Var, Dsts, Rest, Code) ->
+%% Defs = hipe_icode:defines(I),
+%% Uses = hipe_icode:uses(I),
+%% case lists:member(Var, Uses) of
+%% true ->
+%% true;
+%% false ->
+%% case lists:member(Var, Defs) of
+%% true ->
+%% false;
+%% false ->
+%% case hipe_icode:is_branch(I) of
+%% true ->
+%% Succs = hipe_icode:successors(I),
+%% checkSuccsForUses(Succs, Var, Dsts, Rest, Code);
+%% false ->
+%% checkForUses(List, Var, Dsts, [I|Rest], Code)
+%% end
+%% end
+%% end;
+%% checkForUses([], _, _, _, _) -> false.
+
+%% checkSuccsForUses(Succs, Var, Dsts, Rest, Code) ->
+%% checkSuccsForUses(Succs, Var, Dsts, Rest, Code, false).
+%% checkSuccsForUses([S|Succs], Var, Dsts, Rest, Code, Res) ->
+%% List = gotoLabel(S, Code),
+%% Used = checkForUses(List, Var, Dsts, Rest, Code),
+%% checkSuccsForUses(Succs, Var, Code, Dsts, Used andalso Res);
+%% checkSuccsForUses([], _, _, _, _, Res) -> Res.
+
+%% gotoLabel(L, [L|List]) -> List;
+%% gotoLabel(L, [_|List]) -> gotoLabel(L, List);
+%% gotoLabel(_, []) -> [].
+
+
+%% %%>----------------------------------------------------------------------<
+%% % Procedure : removeUnElems/2
+%% % Purpose :
+%% % Arguments :
+%% % Return :
+%% % Notes : Fixa s� att funktionen anv�nder defines(I) ist�llet och
+%% % selektorer ist�llet f�r att matcha p� #call{}. L�tt gjort.
+%% %%>----------------------------------------------------------------------<
+%% removeUnElems(List, Var) -> removeUnElems(List, Var, []).
+%% removeUnElems([#icode_call{'fun'={unsafe_element,_}, args=Var}|List], Var, Res) ->
+%% removeUnElems(List, Var, Res);
+%% removeUnElems([I=#icode_move{dst=Var}|List], [Var], Res) ->
+%% lists:reverse(Res) ++ [I|List];
+%% removeUnElems([I=#icode_call{dstlist=Var}|List], Var, Res) ->
+%% lists:reverse(Res) ++ [I|List];
+%% removeUnElems([I|List], Var, Res) ->
+%% removeUnElems(List, Var, [I|Res]);
+%% removeUnElems([], _, Res) -> lists:reverse(Res).
+
+%% removeUnElems(List, Var) -> removeUnElems(List, Var, []).
+%% removeUnElems([I|List], Var, Res) ->
+%% Defs = hipe_icode:defines(I),
+%% case hipe_icode:is_call(I) of
+%% true ->
+%% Fn = hipe_icode:call_fun(I),
+%% case (hipe_icode:call_args(I) =:= Var) andalso is_tuple(Fn) of
+%% true ->
+%% case element(1,Fn) =:= unsafe_element of
+%% true ->
+%% removeUnElems(List, Var, Res);
+%% false ->
+%% case lists:member(Var, Defs) of
+%% true ->
+%% lists:reverse(Res) ++ [I|List];
+%% false ->
+%% removeUnElems(List, Var, [I|Res])
+%% end
+%% end;
+%% false ->
+%% case lists:member(Var, Defs) of
+%% true ->
+%% lists:reverse(Res) ++ [I|List];
+%% false ->
+%% removeUnElems(List, Var, [I|Res])
+%% end
+%% end;
+%% false ->
+%% case lists:member(Var, Defs) of
+%% true ->
+%% lists:reverse(Res) ++ [I|List];
+%% false ->
+%% removeUnElems(List, Var, [I|Res])
+%% end
+%% end;
+%% removeUnElems([], _, Res) -> lists:reverse(Res).
+
+
+%% Old findDefine that also could update it.
+%% -----------------------------------------
+%% findDefine(Code, Var) -> findDefine(Code, Var, [], []).
+%% findDefine([#icode_call{dstlist=Var,'fun'=mktuple,args=Vs}|Code],Var,NewCode,_)->
+%% findDefine(Code, Var, NewCode, Vs);
+%% findDefine([I=#icode_move{dst=Var, src=Src}|Code], [Var], NewCode, _) ->
+%% case Src of
+%% #icode_var{} ->
+%% findDefine(Code, [Src], [I|NewCode], [Src]);
+%% #icode_const{value={flat, Tuple}} ->
+%% findDefine(Code, [Var], [I|NewCode], []) %% Check this case! [Var]
+%% end;
+%% findDefine([I|Code], Var, NewCode, Vars) ->
+%% findDefine(Code, Var, [I|NewCode], Vars);
+%% findDefine([], _, NewCode, Vars) ->
+%% case Vars of
+%% [] ->
+%% notFound;
+%% [_] ->
+%% {notFound, Vars};
+%% _ ->
+%% {found, lists:reverse(NewCode), Vars}
+%% end.
+
+%% modifyCode(Code, Var) ->
+%% [#icode_return{vars=Var}|Code2] = lists:reverse(Code),
+%% case (length(Var) =< hipe_rtl_arch:nr_of_return_regs()) of
+%% true ->
+%% {Arity, Code3} = modifyCode(Code2, Var, []),
+%% {Arity, Code3};
+%% false ->
+%% {1, Code}
+%% end.
+
+%% modifyCode([I|Code], Var, Res) ->
+%% case scanInstr(I, Var) of
+%% {move, Arity, VarLst} ->
+%% Code2 = [#icode_return{vars=VarLst}, I |lists:reverse(Res) ++ Code],
+%% {Arity, lists:reverse(Code2)};
+%% {mktuple, Arity, VarLst} ->
+%% Code2 = [#icode_return{vars=VarLst}|lists:reverse(Res) ++ Code],
+%% {Arity, lists:reverse(Code2)};
+%% other ->
+%% modifyCode(Code, Var, [I|Res])
+%% end;
+%% modifyCode([], Var, Res) ->
+%% {1, lists:reverse(Res) ++ [#icode_return{vars=Var}]}.
+
+%% scanInstr(#icode_call{dstlist=Var, 'fun'=mktuple, args=Lst}, Var) ->
+%% {mktuple, length(Lst), Lst};
+%% scanInstr(_, _) -> other.
+
+%% printCode(Cfg) ->
+%% Labels = hipe_icode_cfg:labels(Cfg),
+%% {_,_,{_,F,_,_,_,_,_,_},_} = Cfg,
+%% io:format("~nFunction: ~w~n", [F]),
+%% Print = fun(Label) ->
+%% Block = hipe_icode_cfg:bb(Cfg, Label),
+%% Code = hipe_bb:code(Block),
+%% io:format("Label: ~w~n", [Label]),
+%% lists:foreach(fun(I) -> io:format("~w~n", [I]) end, Code),
+%% io:format("~n")
+%% end,
+%% lists:foreach(Print, Labels).
+
+%% printList(File, [{MFA, #icode{code=Code, params=Parms}}|List]) ->
+%% io:format(File, "MFA: ~w - Params: ~w~n", [MFA, Parms]),
+%% printList2(File, Code),
+%% printList(File, List);
+%% printList(_, []) -> ok.
+
+%% printList2(File, []) -> io:format(File, "~n~n", []);
+%% printList2(File, IList) when is_list(IList) ->
+%% [I|List] = IList,
+%% io:format(File, "~w~n", [I]),
+%% printList2(File, List);
+%% printList2(File, SomethingElse) ->
+%% io:format(File, "Got: ~w~n", [SomethingElse]).
+
+%% optimizeDefine([#icode_call{dstlist=Var,'fun'=mktuple,args=Vs}|Code],
+%% Var, _, Res) ->
+%% case Vs of
+%% [_] ->
+%% {none, noOpt};
+%% _ ->
+%% optimizeDefine(Code, Var, Vs, Res)
+%% end;
+%% optimizeDefine([I=#icode_move{dst=Var, src=Src}|Code], [Var], Rets, Res) ->
+%% case hipe_icode:is_var(Src) of
+%% true ->
+%% optimizeDefine(Code, [Src], Rets, Res);
+%% false ->
+%% case Src of
+%% #icode_const{value={flat, Tuple}} when is_tuple(Tuple) ->
+%% optimizeDefine(Code, [Var], tuple_to_list(Tuple), [I|Res]);
+%% #icode_const{value={flat, _}} ->
+%% {none, noOpt};
+%% _ ->
+%% optimizeDefine(Code, [Var], Rets, [I|Res])
+%% end
+%% end;
+%% optimizeDefine([I|Code], Var, Rets, Res) ->
+%% optimizeDefine(Code, Var, Rets, [I|Res]);
+%% optimizeDefine([], Var, Rets, Res) ->
+%% case Rets of
+%% [] ->
+%% {none, Res, Var};
+%% _ ->
+%% {found, Res, Rets}
+%% end.