hipe_icode_fp.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 994 行 · 第 1/2 页
ERL
994 行
%%%-------------------------------------------------------------------%%% File : hipe_icode_fp.erl%%% Author : Tobias Lindahl <tobiasl@it.uu.se>%%% Description : One pass analysis to find floating point values. %%% Mapping to fp variables and creation of fp ebbs.%%%%%% Created : 23 Apr 2003 by Tobias Lindahl <tobiasl@it.uu.se>%%%%%% CVS :%%% $Author: kostis $%%% $Date: 2006/12/15 21:11:54 $%%% $Revision: 1.34 $%%%--------------------------------------------------------------------module(hipe_icode_fp).-export([cfg/1]).-include("hipe_icode.hrl").-record(state, {info, block_map, edge_map, cfg}).cfg(Cfg) -> %%hipe_icode_cfg:pp(Cfg), NewCfg = annotate_fclearerror(Cfg), State = new_state(NewCfg), NewState = place_fp_blocks(State), %%hipe_icode_cfg:pp(state__cfg(NewState)), NewState2 = finalize(NewState), NewCfg1 = state__cfg(NewState2), %%hipe_icode_cfg:pp(NewCfg1), NewCfg2 = unannotate_fclearerror(NewCfg1), NewCfg2.%%____________________________________________________________%%%% Annotate fclearerror with information of the fail label of the%% corresponding fcheckerror.%%annotate_fclearerror(Cfg) -> Labels = hipe_icode_cfg:reverse_postorder(Cfg), annotate_fclearerror(Labels, Cfg).annotate_fclearerror([Label|Left], Cfg) -> BB = hipe_icode_cfg:bb(Cfg, Label), Code = hipe_bb:code(BB), NewCode = annotate_fclearerror1(Code, Label, Cfg, []), NewBB = hipe_bb:code_update(BB, NewCode), NewCfg = hipe_icode_cfg:bb_add(Cfg, Label, NewBB), annotate_fclearerror(Left, NewCfg);annotate_fclearerror([], Cfg) -> Cfg.annotate_fclearerror1([I|Left], Label, Cfg, Acc) -> case I of #call{} -> case hipe_icode:call_fun(I) of fclearerror -> Fail = lookahead_for_fcheckerror(Left, Label, Cfg), NewI = hipe_icode:call_fun_update(I, {fclearerror, Fail}), annotate_fclearerror1(Left, Label, Cfg, [NewI|Acc]); _ -> annotate_fclearerror1(Left, Label, Cfg, [I|Acc]) end; _ -> annotate_fclearerror1(Left, Label, Cfg, [I|Acc]) end;annotate_fclearerror1([], _Label, _Cfg, Acc) -> lists:reverse(Acc).lookahead_for_fcheckerror([I|Left], Label, Cfg) -> case I of #call{} -> case hipe_icode:call_fun(I) of fcheckerror -> hipe_icode:call_fail_label(I); _ -> lookahead_for_fcheckerror(Left, Label, Cfg) end; _ -> lookahead_for_fcheckerror(Left, Label, Cfg) end;lookahead_for_fcheckerror([], Label, Cfg) -> case hipe_icode_cfg:succ(hipe_icode_cfg:succ_map(Cfg), Label) of [] -> exit("Unterminated fp ebb"); SuccList -> Succ = hd(SuccList), Code = hipe_bb:code(hipe_icode_cfg:bb(Cfg, Label)), lookahead_for_fcheckerror(Code, Succ, Cfg) end.unannotate_fclearerror(Cfg) -> Labels = hipe_icode_cfg:reverse_postorder(Cfg), unannotate_fclearerror(Labels, Cfg).unannotate_fclearerror([Label|Left], Cfg) -> BB = hipe_icode_cfg:bb(Cfg, Label), Code = hipe_bb:code(BB), NewCode = unannotate_fclearerror1(Code, []), NewBB = hipe_bb:code_update(BB, NewCode), NewCfg = hipe_icode_cfg:bb_add(Cfg, Label, NewBB), unannotate_fclearerror(Left, NewCfg);unannotate_fclearerror([], Cfg) -> Cfg.unannotate_fclearerror1([I|Left], Acc) -> case I of #call{} -> case hipe_icode:call_fun(I) of {fclearerror, _Fail} -> NewI = hipe_icode:call_fun_update(I, fclearerror), unannotate_fclearerror1(Left, [NewI|Acc]); _ -> unannotate_fclearerror1(Left, [I|Acc]) end; _ -> unannotate_fclearerror1(Left, [I|Acc]) end;unannotate_fclearerror1([], Acc) -> lists:reverse(Acc).%%____________________________________________________________%%%% Make float ebbs%%place_fp_blocks(State)-> WorkList = new_worklist(State), transform_block(WorkList, State).transform_block(WorkList, State) -> case get_work(WorkList) of none -> State; {Label, NewWorkList} -> %%io:format("Handling ~w \n", [Label]), BB = state__bb(State, Label), Code = hipe_bb:code(BB), NofPreds = length(state__pred(State, Label)), Map = state__map(State, Label), FilteredMap = filter_map(Map, NofPreds), %%io:format("Label: ~w\nPhiMap: ~p\nFilteredMap ~p\n", %% [Label, gb_trees:to_list(Map), gb_trees:to_list(FilteredMap)]), {Prelude, NewFilteredMap} = do_prelude(FilteredMap), {NewMap, NewCode} = transform_instrs(Code, Map, NewFilteredMap, []), NewBB = hipe_bb:code_update(BB, Prelude++NewCode), NewState = state__bb_add(State, Label, NewBB), case state__map_update(NewState, Label, NewMap) of fixpoint -> transform_block(NewWorkList, NewState); NewState1 -> Succ = state__succ(NewState1, Label), NewWorkList1 = add_work(NewWorkList, Succ), transform_block(NewWorkList1, NewState1) end end.transform_instrs([I|Left], PhiMap, Map, Acc) -> Defines = hipe_icode:defines(I), NewMap = delete_all(Defines, Map), NewPhiMap = delete_all(Defines, PhiMap), case I of #phi{} -> Uses = hipe_icode:uses(I), case [X || X <- Uses, lookup(X, PhiMap) =/= none] of [] -> %% No ordinary variables from the argument has been untagged. transform_instrs(Left, NewPhiMap, NewMap, [I|Acc]); Uses -> %% All arguments are untagged. Let's untag the destination. Dst = hipe_icode:phi_dst(I), NewDst = hipe_icode:mk_new_fvar(), NewMap1 = gb_trees:enter(Dst, NewDst, NewMap), NewI = subst_phi_uncond(I, NewDst, PhiMap), transform_instrs(Left, NewPhiMap, NewMap1, [NewI|Acc]); _ -> %% Some arguments are untagged. Keep the destination. Dst = hipe_icode:phi_dst(I), NewI = subst_phi(I, Dst, PhiMap), transform_instrs(Left, NewPhiMap, NewMap, [NewI|Acc]) end; #call{} -> case hipe_icode:call_fun(I) of X when X =:= unsafe_untag_float orelse X =:= conv_to_float -> [Dst] = hipe_icode:defines(I), case hipe_icode:uses(I) of [] -> %% Constant transform_instrs(Left, NewPhiMap, NewMap, [I|Acc]); [Src] -> case lookup(Src, Map) of none -> NewMap1 = gb_trees:enter(Src, {assigned, Dst}, NewMap), transform_instrs(Left, NewPhiMap, NewMap1, [I|Acc]); Dst -> %% This is the instruction that untagged the variable. %% Use old maps. transform_instrs(Left, NewPhiMap, Map, [I|Acc]); FVar -> %% The variable was already untagged. %% This instruction can be changed to a fmove. NewI = hipe_icode:mk_fmove(Dst, FVar), case hipe_icode:call_continuation(I) of [] -> transform_instrs(Left,NewPhiMap,NewMap,[NewI|Acc]); ContLbl -> Goto = hipe_icode:mk_goto(ContLbl), transform_instrs(Left, NewPhiMap, NewMap, [Goto, NewI|Acc]) end end end; unsafe_tag_float -> [Dst] = hipe_icode:defines(I), [Src] = hipe_icode:uses(I), NewMap1 = gb_trees:enter(Dst, {assigned, Src}, NewMap), transform_instrs(Left, NewPhiMap, NewMap1,[I|Acc]); _ -> {NewMap1, NewAcc} = check_for_fop_candidates(I, NewMap, Acc), transform_instrs(Left, NewPhiMap, NewMap1, NewAcc) end; _ -> NewIns = handle_untagged_arguments(I, NewMap), transform_instrs(Left, NewPhiMap, NewMap, NewIns ++ Acc) end;transform_instrs([], _PhiMap, Map, Acc) -> {Map, lists:reverse(Acc)}.check_for_fop_candidates(I, Map, Acc)-> case is_fop_cand(I) of false -> NewIs = handle_untagged_arguments(I, Map), {Map, NewIs ++ Acc}; true -> Fail = hipe_icode:call_fail_label(I), Cont = hipe_icode:call_continuation(I), Op = fun_to_fop(hipe_icode:call_fun(I)), case Fail of [] -> Args = hipe_icode:args(I), ConstArgs = [X || X <- Args, hipe_icode:is_const(X)], case catch [float(hipe_icode:const_value(X)) || X <- ConstArgs] of {'EXIT', _} -> %% This instruction will fail at runtime. The warning %% should already have happened in hipe_icode_type. NewIs = handle_untagged_arguments(I, Map), {Map, NewIs ++ Acc}; _ -> %%io:format("Changing ~w to ~w\n", [hipe_icode:call_fun(I), Op]), Uses = hipe_icode:uses(I), Defines = hipe_icode:defines(I), Convs = [X||X <- remove_duplicates(Uses), lookup(X, Map) =:= none], NewMap0 = add_new_bindings_assigned(Convs, Map), NewMap = add_new_bindings_unassigned(Defines, NewMap0), ConvIns = get_conv_instrs(Convs, NewMap), NewI = hipe_icode:mk_primop(lookup_list(Defines, NewMap), Op, lookup_list_keep_consts(Args,NewMap), Cont, Fail), NewI2 = conv_consts(ConstArgs, NewI), {NewMap, [NewI2|ConvIns]++Acc} end; _ -> %% Bailing out! Can't handle instructions in catches (yet). NewIs = handle_untagged_arguments(I, Map), {Map, NewIs ++ Acc} end end.%% If this is an instruction that needs to operate on tagged values,%% which currently are untagged, we must tag the values and perhaps%% end the fp ebb.handle_untagged_arguments(I, Map)-> case lists:filter(fun(X)-> must_be_tagged(X, Map) end, hipe_icode:uses(I)) of [] -> [I]; Tag -> TagIntrs = [hipe_icode:mk_primop([Dst], unsafe_tag_float, [gb_trees:get(Dst, Map)]) || Dst<-Tag], [I|TagIntrs] end.%% Add phi nodes for untagged fp values.do_prelude(Map)-> case gb_trees:lookup(phi, Map) of none -> {[], Map}; {value, List} -> %%io:format("Adding phi: ~w\n", [List]), Fun = fun({FVar, Bindings}, Acc) -> [hipe_icode:mk_phi(FVar, Bindings)|Acc] end, {lists:foldl(Fun, [], List), gb_trees:delete(phi, Map)} end.split_code(Code) -> split_code(Code, []).split_code([I], Acc) -> {lists:reverse(Acc), I};split_code([I|Left], Acc)-> split_code(Left, [I|Acc]).%% When all code is mapped to fp instructions we must make sure that%% the fp ebb information goin in to each block is the same as the%% information coming out of each predecessor. Otherwise, we must add%% a block in between.finalize(State) -> Worklist = new_worklist(State), NewState = place_error_handling(Worklist, State), Edges = needs_fcheckerror(NewState), finalize(Edges, NewState).finalize([{From, To}|Left], State) -> NewState = add_fp_ebb_fixup(From, To, State), finalize(Left, NewState);finalize([], State) -> State.needs_fcheckerror(State) -> Cfg = state__cfg(State), Labels = hipe_icode_cfg:labels(Cfg), needs_fcheckerror(Labels, State, []).needs_fcheckerror([Label|Left], State, Acc) -> case state__get_in_block_in(State, Label) of {true, _} -> needs_fcheckerror(Left, State, Acc); false -> Pred = state__pred(State, Label), case [X || X <- Pred, state__get_in_block_out(State, X) =/= false] of [] -> needs_fcheckerror(Left, State, Acc); NeedsFcheck -> case length(Pred) =:= length(NeedsFcheck) of true -> %% All edges needs fcheckerror. Add this to the %% beginning of the block instead. needs_fcheckerror(Left, State, [{none, Label}|Acc]); false -> Edges = [{X, Label} || X <- NeedsFcheck], needs_fcheckerror(Left, State, Edges ++ Acc) end end end;needs_fcheckerror([], _State, Acc) -> Acc.add_fp_ebb_fixup('none', To, State) -> %% Add the fcheckerror to the start of the block. BB = state__bb(State, To), Code = hipe_bb:code(BB), Phis = lists:takewhile(fun(X) -> hipe_icode:is_phi(X) end, Code), TailCode = lists:dropwhile(fun(X) -> hipe_icode:is_phi(X) end, Code), FC = hipe_icode:mk_primop([], fcheckerror, []), NewCode = Phis ++ [FC|TailCode], state__bb_add(State, To, hipe_bb:code_update(BB, NewCode));add_fp_ebb_fixup(From, To, State) -> FCCode = [hipe_icode:mk_primop([], fcheckerror, [], To, [])], FCBB = hipe_bb:mk_bb(FCCode), FCLabel = hipe_icode:label_name(hipe_icode:mk_new_label()), NewState = state__bb_add(State, FCLabel, FCBB), NewState1 = state__redirect(NewState, From, To, FCLabel), ToBB = state__bb(NewState, To), ToCode = hipe_bb:code(ToBB), NewToCode = redirect_phis(ToCode, From, FCLabel), NewToBB = hipe_bb:code_update(ToBB, NewToCode), state__bb_add(NewState1, To, NewToBB).redirect_phis(Code, OldFrom, NewFrom)-> redirect_phis(Code, OldFrom, NewFrom, []).redirect_phis([I|Left], OldFrom, NewFrom, Acc)-> case I of #phi{} -> NewI = hipe_icode:phi_redirect_pred(I, OldFrom, NewFrom), redirect_phis(Left, OldFrom, NewFrom, [NewI|Acc]); _ -> lists:reverse(Acc)++[I|Left] end;redirect_phis([], _OldFrom, _NewFrom, Acc) -> lists:reverse(Acc).subst_phi(I, Dst, Map) -> ArgList = subst_phi_uses0(hipe_icode:phi_arglist(I), Map, []), hipe_icode:mk_phi(Dst, ArgList).subst_phi_uses0([{Pred, Var}|Left], Map, Acc) -> case gb_trees:lookup(Var, Map) of {value, List} -> case lists:keysearch(Pred, 1, List) of {value, {Pred, {assigned, _NewVar}}} -> %% The variable is untagged, but it has been assigned. Keep it! subst_phi_uses0(Left, Map, [{Pred, Var}|Acc]); {value, {Pred, NewVar}}-> %% The variable is untagged and it has never been assigned as tagged. subst_phi_uses0(Left, Map, [{Pred, NewVar}|Acc]); false -> %% The variable is not untagged. subst_phi_uses0(Left, Map, [{Pred, Var}|Acc]) end; none -> %% The variable is not untagged. subst_phi_uses0(Left, Map, [{Pred, Var}|Acc]) end;subst_phi_uses0([], _Map, Acc) -> Acc.subst_phi_uncond(I, Dst, Map) -> ArgList = subst_phi_uses_uncond0(hipe_icode:phi_arglist(I), Map, []), hipe_icode:mk_phi(Dst, ArgList).subst_phi_uses_uncond0([{Pred, Var}|Left], Map, Acc) -> case gb_trees:lookup(Var, Map) of {value, List} -> case lists:keysearch(Pred, 1, List) of {value, {Pred, {assigned, NewVar}}} -> %% The variable is untagged! subst_phi_uses_uncond0(Left, Map, [{Pred, NewVar}|Acc]); {value, {Pred, NewVar}}-> %% The variable is untagged! subst_phi_uses_uncond0(Left, Map, [{Pred, NewVar}|Acc]); false -> %% The variable is not untagged. subst_phi_uses_uncond0(Left, Map, [{Pred, Var}|Acc]) end; none -> %% The variable is not untagged. subst_phi_uses_uncond0(Left, Map, [{Pred, Var}|Acc]) end;subst_phi_uses_uncond0([], _Map, Acc) -> Acc.place_error_handling(WorkList, State) -> case get_work(WorkList) of none -> State; {Label, NewWorkList} -> BB = state__bb(State, Label), Code = hipe_bb:code(BB), case state__join_in_block(State, Label) of fixpoint -> place_error_handling(NewWorkList, State); {NewState, NewInBlock} -> {NewCode1, InBlockOut} = place_error(Code, NewInBlock, []), Succ = state__succ(NewState, Label), NewCode2 = handle_unchecked_end(Succ, NewCode1, InBlockOut), NewBB = hipe_bb:code_update(BB, NewCode2), NewState1 = state__bb_add(NewState, Label, NewBB), NewState2 = state__in_block_out_update(NewState1, Label, InBlockOut), NewWorkList1 = add_work(NewWorkList, Succ), place_error_handling(NewWorkList1, NewState2) end end.place_error([I|Left], InBlock, Acc) -> case I of #call{} -> case hipe_icode:call_fun(I) of X when X =:= fp_add; X =:= fp_sub; X =:= fp_mul; X =:= fp_div; X =:= fnegate -> case InBlock of false -> Clear = hipe_icode:mk_primop([], {fclearerror, []}, []), place_error(Left, {true, []}, [I, Clear|Acc]); {true, _} -> place_error(Left, InBlock, [I|Acc]) end; unsafe_tag_float -> case InBlock of {true, Fail} -> Check = hipe_icode:mk_primop([], fcheckerror, [], [], Fail), place_error(Left, false, [I, Check|Acc]); false -> place_error(Left, InBlock, [I|Acc]) end; {fclearerror, Fail} -> case InBlock of {true, Fail} -> %% We can remove this fclearerror! case hipe_icode:call_continuation(I) of [] -> place_error(Left, InBlock, Acc); Cont -> place_error(Left, InBlock, [hipe_icode:mk_goto(Cont)|Acc]) end; {true, _OtherFail} ->
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?