From 84adefa331c4159d432d22840663c38f155cd4c1 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Fri, 20 Nov 2009 14:54:40 +0000 Subject: The R13B03 release. --- lib/hipe/icode/hipe_icode_mulret.erl | 1323 ++++++++++++++++++++++++++++++++++ 1 file changed, 1323 insertions(+) create mode 100644 lib/hipe/icode/hipe_icode_mulret.erl (limited to 'lib/hipe/icode/hipe_icode_mulret.erl') 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 +%% Purpose : +%% Created : 23 Jun 2004 by Christoffer Vikström +%%---------------------------------------------------------------------- + +-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. -- cgit v1.2.3