hipe_icode_split_arith.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 535 行 · 第 1/2 页
ERL
535 行
%% -*- erlang-indent-level: 2 -*-%%-------------------------------------------------------------------%% File : hipe_icode_split_arith.erl%% Author : Tobias Lindahl <tobiasl@csd.uu.se>%% Description : %%%% Created : 12 Nov 2003 by Tobias Lindahl <tobiasl@csd.uu.se>%%--------------------------------------------------------------------module(hipe_icode_split_arith).-export([cfg/3]).-include("hipe_icode.hrl").-define(MIN_RATIO, 0.005).cfg(Cfg, _Fun, Options) -> Icode = hipe_icode_cfg:cfg_to_linear(Cfg), case proplists:get_bool(split_arith_unsafe, Options) of true -> make_split_unsafe(Icode); _ -> case preprocess(Icode) of {do_not_split, _Ratio} -> Cfg; {split, _Ratio, Icode1} -> NewCfg = split(Icode1), %%hipe_icode_cfg:pp(NewCfg), NewCfg end end.check_nofix_const([Arg1|Arg2]) -> case hipe_icode:is_const(Arg1) of true -> %%io:format("ConsTant.....~w",[Arg1]), Val1 = hipe_tagscheme:fixnum_val(hipe_icode:const_value(Arg1)), case hipe_tagscheme:is_fixnum(Val1) of true -> check_nofix_const(Arg2); false -> {no} end; false -> check_nofix_const(Arg2) end; check_nofix_const([]) -> true.check_const([I|Left]) -> case I of #call{} -> case is_arith(I) of true -> %%io:format("is_arith.....~w",[I]), Args = hipe_icode:call_args(I), case check_nofix_const(Args) of {no} -> {do_not_split}; _ -> check_const(Left) end; _ -> check_const(Left) end; _ -> check_const(Left) end;check_const([]) -> {yes}.make_split_unsafe(Icode)-> LinearCode = hipe_icode:icode_code(Icode), NewLinearCode = change_unsafe(LinearCode), NewIcode = hipe_icode:icode_code_update(Icode, NewLinearCode), hipe_icode_cfg:linear_to_cfg(NewIcode).change_unsafe([I|Is]) -> case I of #call{} -> case is_arith_extra_unsafe(I) of true -> NewOp = arithop_to_extra_unsafe(hipe_icode:call_fun(I)), NewI1 = hipe_icode:call_fun_update(I, NewOp), [NewI1|change_unsafe(Is)]; false -> [I|change_unsafe(Is)] end; _ -> [I|change_unsafe(Is)] end;change_unsafe([]) -> [].preprocess(Icode) -> LinearCode = hipe_icode:icode_code(Icode), case check_const(LinearCode) of {do_not_split} -> %%io:format("NO FIXNUM....."), {do_not_split, 1.9849 }; % Ratio val is ignored _ -> {NofArith, NofIns, NewLinearCode} = preprocess_code(LinearCode), case NofArith / NofIns of X when X >= ?MIN_RATIO -> NewIcode = hipe_icode:icode_code_update(Icode, NewLinearCode), {split, X, NewIcode}; Y -> {do_not_split, Y} end end.preprocess_code([H|Code]) -> preprocess_code(Code, 0, 0, [H]).preprocess_code([I|Left], NofArith, NofIns,CodeAcc = [PrevI|_])-> case I of #call{} -> case is_arith(I) of true -> %% Note that we need to put these instructions in a separate %% basic block since we need the ability to fail to these %% instructions, but also fail from them. The basic block %% merger will take care of unnecessary splits. %% If call is an arithmetic operation replace the operation %% with the specified replacement operator. NewOp = arithop_to_split(hipe_icode:call_fun(I)), NewI = hipe_icode:call_fun_update(I, NewOp), case hipe_icode:is_label(PrevI) of true -> case (Left =:= []) orelse hipe_icode:is_label(hd(Left)) of true -> preprocess_code(Left, NofArith+1, NofIns+1, [NewI|CodeAcc]); false -> NewLabel = hipe_icode:mk_new_label(), NewLabelName = hipe_icode:label_name(NewLabel), NewI1 = hipe_icode:call_set_continuation(NewI, NewLabelName), preprocess_code(Left, NofArith+1, NofIns+1, [NewLabel, NewI1|CodeAcc]) end; false -> RevPreCode = case hipe_icode:is_branch(PrevI) of true -> [hipe_icode:mk_new_label()]; false -> NewLabel1 = hipe_icode:mk_new_label(), NewLabelName1 = hipe_icode:label_name(NewLabel1), [NewLabel1, hipe_icode:mk_goto(NewLabelName1)] end, case (Left =:= []) orelse hipe_icode:is_label(hd(Left)) of true -> preprocess_code(Left, NofArith+1, NofIns+1, [NewI|RevPreCode] ++ CodeAcc); false -> NewLabel2 = hipe_icode:mk_new_label(), NewLabelName2 = hipe_icode:label_name(NewLabel2), NewI1 = hipe_icode:call_set_continuation(NewI, NewLabelName2), preprocess_code(Left, NofArith+1, NofIns+1, [NewLabel2, NewI1|RevPreCode] ++ CodeAcc) end end; false -> preprocess_code(Left, NofArith, NofIns + 1, [I|CodeAcc]) end; #label{} -> %% Don't count labels as instructions. preprocess_code(Left, NofArith, NofIns, [I|CodeAcc]); _ -> preprocess_code(Left, NofArith, NofIns+1, [I|CodeAcc]) end;preprocess_code([], NofArith, NofIns, CodeAcc) -> {NofArith, NofIns, lists:reverse(CodeAcc)}.split(Icode) -> LinearCode = hipe_icode:icode_code(Icode), %% create a new icode label for each existing icode label %% create mappings, NewToOld and OldToNew. %% AllLabels = lists:foldl(fun(I, Acc) -> case hipe_icode:is_label(I) of true -> [hipe_icode:label_name(I)|Acc]; false -> Acc end end, [], LinearCode), {OldToNewMap, NewToOldMap} = new_label_maps(AllLabels), %% the call below doubles the number of basic blocks with the new %% labels instead of the old. NewLinearCode = map_code(LinearCode, OldToNewMap), NewIcode = hipe_icode:icode_code_update(Icode, NewLinearCode), NewCfg = hipe_icode_cfg:linear_to_cfg(NewIcode), NewCfg2 = insert_tests(NewCfg, [gb_trees:get(X, OldToNewMap) || X<-AllLabels], NewToOldMap, OldToNewMap), %%io:format("split(Cfg): Inserting testsL Done\n", []), NewCfg2.map_code(OldCode, LabelMap) -> AddedCode = map_code(OldCode, none, LabelMap, []), OldCode ++ AddedCode.map_code([I|Left], ArithFail, LabelMap, Acc) -> case I of #call{} -> case is_arith(I) of true -> case hipe_icode:defines(I) of []-> map_code(Left, ArithFail, LabelMap, [redirect(I, LabelMap)|Acc]); _ -> NewOp = split_to_unsafe(I), NewI1 = hipe_icode:call_fun_update(I, NewOp), NewI2 = redirect(NewI1, LabelMap), NewI3 = hipe_icode:call_set_fail_label(NewI2, ArithFail), map_code(Left, ArithFail, LabelMap, [NewI3|Acc]) end; false -> map_code(Left, ArithFail, LabelMap, [redirect(I, LabelMap)|Acc]) end; #label{} -> LabelName = hipe_icode:label_name(I), NewLabel = hipe_icode:mk_label(gb_trees:get(LabelName, LabelMap)), map_code(Left, LabelName, LabelMap, [NewLabel|Acc]); _ -> map_code(Left, ArithFail, LabelMap, [redirect(I, LabelMap)|Acc]) end;map_code([], _ArithFail, _LabelMap, Acc) -> lists:reverse(Acc).insert_tests(Cfg, Labels,NewToOldMap, OldToNewMap) -> InfoMap = infomap_init(Labels), %%io:format("insert_tests/3: Finding testpoints ...\n", []), NewInfoMap = find_testpoints(Cfg, Labels, InfoMap), %%io:format("insert_tests/3: Finding testpoints: Done\n", []), %%io:format("insert_tests/3: Infomap: ~w\n", [gb_trees:to_list(NewInfoMap)]), make_tests(Cfg, NewInfoMap, NewToOldMap, OldToNewMap).find_testpoints(Cfg, Labels, InfoMap) -> case find_testpoints(Labels, InfoMap, Cfg, false) of {dirty, NewInfoMap} -> %%io:format("find_testpoints/3: Looping\n", []), find_testpoints(Cfg, Labels, NewInfoMap); fixpoint -> InfoMap end.find_testpoints([Lbl|Left], InfoMap, Cfg, Dirty) -> Code = hipe_bb:code(hipe_icode_cfg:bb(Cfg, Lbl)), InfoOut = join_info(hipe_icode_cfg:succ(Cfg, Lbl), InfoMap), OldInfoIn = infomap_get_all(Lbl, InfoMap), NewInfoIn = traverse_code(lists:reverse(Code), InfoOut), case (gb_sets:is_subset(OldInfoIn, NewInfoIn) andalso gb_sets:is_subset(NewInfoIn, OldInfoIn)) of true -> find_testpoints(Left, InfoMap, Cfg, Dirty); false -> %%io:format("find_testpoints/4: Label: ~w: OldMap ~w\nNewMap: ~w\n", %% [Lbl, gb_sets:to_list(OldInfoIn), gb_sets:to_list(NewInfoIn)]), NewInfoMap = gb_trees:update(Lbl, NewInfoIn, InfoMap), find_testpoints(Left, NewInfoMap, Cfg, true) end;find_testpoints([], InfoMap, _Cfg, Dirty) -> if Dirty -> {dirty, InfoMap}; true -> fixpoint end.traverse_code([I|Left], Info) -> NewInfo = kill_defines(I, Info), case I of #call{} -> case is_unsafe_arith(I) of true -> %% The dst is sure to be a fixnum. Remove the 'killed' mark. Dst = hd(hipe_icode:call_dstlist(I)),
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?