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 + -
显示快捷键?