hipe_finalize.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 456 行

ERL
456
字号
%% -*- erlang-indent-level: 2 -*-%% ====================================================================%%  File    :  hipe_finalize%%  Purpose :%% ====================================================================%% @doc%@end%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-module(hipe_finalize).-export([%% straighten/1,	 split_constants/1]).%-ifndef(DEBUG).%-define(DEBUG,1).%-endif.%-define(TIMING,true).-include("../main/hipe.hrl").-include("hipe_sparc.hrl").%% hipe:c({beam_inv_opcodes,opcode,1},[o2,time]).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Makes the code possible to linearize without code duplication.%% Basic blocks are merged when possible.%%%% straighten(CFG) ->%%   %% hipe_sparc_cfg:pp(CFG),%%   ?TIME_STMNT(Lbls = hipe_sparc_cfg:depth_first_ordering(CFG),%% 	      "Ordering took: ", Otime),%%   ?TIME_STMNT(CFG1 = straighten(Lbls,CFG,CFG,none_visited()),%% 	      "Straigthtening took: ", STime),%%   ?IF_DEBUG(hipe_sparc_cfg:pp(CFG1),true),%%   CFG1.%% %% straighten([Lbl|Ls],CFG,NewCFG,Visited) ->%%   ?debug_msg("Visiting ~w~n",[Lbl]),%%   Vis0 = visit(Lbl, Visited),%%   BB = hipe_sparc_cfg:bb(CFG, Lbl),%%   Jmp = hipe_bb:last(BB),%%   case is_cond(Jmp) of%%     true ->%%       %% Switch the jump so the common case is not taken%%       Pred = cond_pred(Jmp),%%       Jmp0 =%% 	if Pred >= 0.5 ->%% 	    %% io:format("Switching ~w~n", [Jmp]),%% 	    switch_cond(Jmp);%% 	   true ->%% 	    Jmp%% 	end,%%       FallTrough = cond_false_label(Jmp0),%% 	  %% We have to insert a goto (the falltrough is%% 	  %% somewhere else (or duplicate the code))%% 	  ?debug_msg("Need goto to ~w~n", [FallTrough]),%% 	  NewFT = hipe_sparc:label_create_new(),%% 	  NewFTName = hipe_sparc:label_name(NewFT),%% 	  Jmp1 = cond_false_label_update(Jmp0, NewFTName),%% 	  Goto = hipe_sparc:goto_create(FallTrough, []),%% 	  GotoBB = hipe_bb:mk_bb([Goto]),%% 	  CFG0 = hipe_sparc_cfg:bb_add(NewCFG, NewFTName, GotoBB),%%       NewBBCode = hipe_bb:butlast(BB) ++ [Jmp1],%%       NewBB = hipe_bb:code_update(BB, NewBBCode),%%       CFG1 = hipe_sparc_cfg:bb_add(CFG0, Lbl, NewBB),%% %%       straighten(Ls, CFG, CFG1, Vis0);%%     false ->%%       case Jmp of %% 	#jmp{} ->%% 	  straighten(Ls++hipe_sparc:jmp_destinations(Jmp), CFG, NewCFG, Vis0);%% 	_ ->%% 	  straighten(Ls, CFG, NewCFG, Vis0)%%       end%%   end;%% straighten([],_,CFG,_) -> CFG.%% -------------------------------------------------------------------%% A couple of functions that provide a common interface to both b-%% and br- branches%% -------------------------------------------------------------------%% is_cond(I) ->%%   case I of%%     #br{} -> true;%%     #b{} -> true;%%     _ -> false%%   end.%% %% cond_pred(I) ->%%   case I of%%     #br{} -> hipe_sparc:br_pred(I);%%     #b{} -> hipe_sparc:b_pred(I)%%   end.%% %% cond_false_label(B) ->%%   case B of%%     #br{} -> hipe_sparc:br_false_label(B);%%     #b{} -> hipe_sparc:b_false_label(B)%%   end.%% %% cond_false_label_update(B, NewTrue) ->%%   case B of%%     #br{} -> hipe_sparc:br_false_label_update(B, NewTrue);%%     #b{} -> hipe_sparc:b_false_label_update(B, NewTrue)%%   end.%% %% switch_cond(B) ->%%   case B of%%     #br{} -> switch_br(B);%%     #b{} -> switch_b(B)%%   end.%%%% Negate the cc and change the labels of a register branch%%%% switch_br(B) ->%%   CC = hipe_sparc:cc_negate(hipe_sparc:br_regcond(B)),%%   True = hipe_sparc:br_true_label(B),%%   False = hipe_sparc:br_false_label(B),%%   Pred = 1 - hipe_sparc:br_pred(B),%%   B0 = hipe_sparc:br_regcond_update(B, CC),%%   B1 = hipe_sparc:br_true_label_update(B0, False),%%   B2 = hipe_sparc:br_false_label_update(B1, True),%%   hipe_sparc:br_pred_update(B2, Pred).%%%% Negate the cc and change the labels of a branch%%%% switch_b(B) ->%%   CC = hipe_sparc:cc_negate(hipe_sparc:b_cond(B)),%%   True = hipe_sparc:b_true_label(B),%%   False = hipe_sparc:b_false_label(B),%%   Pred = 1 - hipe_sparc:b_pred(B),%%   B0 = hipe_sparc:b_cond_update(B, CC),%%   B1 = hipe_sparc:b_true_label_update(B0, False),%%   B2 = hipe_sparc:b_false_label_update(B1, True),%%   hipe_sparc:b_pred_update(B2, Pred).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Does the final layout of the code and fills delay slots.  After%% this pass the code cannot be converted back to a CFG.%%%finalize_succ(none, CFG, Vis) ->%   {Vis, []};%finalize_succ(Label, CFG, Vis) ->%   case visited(Label, Vis) of%      true ->%	 {Vis, []};      % already visited%      false ->%	 Vis0 = visit(Label, Vis),%	 BB = hipe_sparc_cfg:bb(CFG, Label),%	 Fallthrough = hipe_sparc_cfg:fallthrough(CFG, Label),%	 Cond = hipe_sparc_cfg:conditional(CFG, Label),%	 %% If Label got only one successor thats not been visited we can%	 %% remove the jump.%	 case {Fallthrough, Cond} of%	    {Lbl, none} when Lbl =/= none -> %	       case visited(Lbl, Vis0) of%		  true -> Merge = false;%		  false -> Merge = true%	       end;%	    _ -> Merge = false%	 end,%	 if Merge =:= true ->%	       LblInstr = hipe_sparc:label_create(Label, hipe_bb:annot(BB)),%	       Code = hipe_bb:butlast(BB),%	       {Vis1, Code1} = finalize_succ(Fallthrough, CFG, Vis0),%	       {Vis1, [[LblInstr|fill_delay(Code)], Code1]};%	    true ->%	       LblInstr = hipe_sparc:label_create(Label, hipe_bb:annot(BB)),%	       Code = hipe_bb:code(BB),%	       {Vis1, Code1} = finalize_succ(Fallthrough, CFG, Vis0),%	       {Vis2, Code2} = finalize_succ(Cond, CFG, Vis1),%	       {Vis2, [[LblInstr|fill_delay(Code)], Code1, Code2]}%	 end%   end.%% Code is a list of instructions (from one basic block).%%fill_delay(Code) ->%   Code0 = peephole(Code),%   Codes = split_at_branch(Code0),%   lists:map(fun fill_delay0/1, Codes).%% Code is a list of instructions where a branch/jump %%fill_delay0(Code) ->%   case catch find_delay(Code) of%      no_branch ->%	 Code;%      {NewCode, _, _} ->%	 [NewCode | [hipe_sparc:nop_create([])]];%      {NewCode, Delay} ->%	 [NewCode | [Delay]]%   end.%% Extracts a delay instruction from a list %%find_delay([Jmp]) ->%   case hipe_sparc:is_any_branch(Jmp) of%      true ->%	 {[Jmp], %	  ordsets:from_list(hipe_sparc:uses(Jmp)), %	  ordsets:from_list(hipe_sparc:defines(Jmp))};%      false ->%	 throw(no_branch)%   end;%find_delay([I|Is]) ->%   case find_delay(Is) of%      {NewIs, Uses, Defs} ->%	 IUses = ordsets:from_list(hipe_sparc:uses(I)),%	 IDefs = ordsets:from_list(hipe_sparc:defines(I)),%	 NewUses = ordsets:union(Uses, IUses),%	 NewDefs = ordsets:union(Defs, IDefs),%	 case is_delay_instr(I) of%	    true ->%	       %% Make sure the instruction isn't defining a reg that is %	       %% used later or uses a reg that is defined later or%	       %% defines a reg that is defined later%	       X = {ordsets:intersection(Uses, IDefs), %		    ordsets:intersection(Defs, IUses),%		    ordsets:intersection(Defs, IDefs)},%	       case X of%		  {[], [], []} ->  %% No conflicts, found a delay instr.%		     {NewIs, I};%		  _ ->%		     {[I|NewIs], NewUses, NewDefs}%	       end;%	    false ->%	       {[I|NewIs], NewUses, NewDefs}%	 end;%      {NewIs, Delay} ->%	 {[I|NewIs], Delay}%   end.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% none_visited() ->%%   sets:new().%% %% visit(X, Vis) -> %%   sets:add_element(X, Vis).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Replaces big immediates with registers that are defined with%% a 'sethi' and an 'or'. %%%% NEWSFLASH! This also checks if arg1 to an alu operation is an immediate%% and rectifies that situation.%%%% NEWSFLASH! 990823%% This also checks if the source of a store operation is an immediate%% and rectifies that situation.%%split_constants(CFG) ->  Labels = hipe_sparc_cfg:labels(CFG),  split_bbs(Labels, CFG).split_bbs([], CFG) ->  CFG;split_bbs([Lbl|Lbls], CFG) ->  BB = hipe_sparc_cfg:bb(CFG, Lbl),  Code = hipe_bb:code(BB),  case split_instrs(Code, [], unchanged) of    unchanged ->      split_bbs(Lbls, CFG);    NewCode ->      NewCFG = hipe_sparc_cfg:bb_add(CFG, Lbl, hipe_bb:code_update(BB,NewCode)),      split_bbs(Lbls, NewCFG)  end.split_instrs([], _RevCode, unchanged) ->  unchanged;split_instrs([], RevCode, changed) ->  lists:reverse(RevCode);split_instrs([I0|Is], RevCode, Status) ->  case fix_addressing_mode(I0) of      unchanged ->	 case split_instr(I0) of	    unchanged ->	       split_instrs(Is, [I0|RevCode], Status);	    NewCode ->	       split_instrs(Is, NewCode++RevCode, changed)	 end;      NewCode ->	 split_instrs(NewCode++Is, RevCode, changed)   end.%%%% Ensure that correct addressing modes are used.%%fix_addressing_mode(I) ->  case I of    #alu{} ->      Src1 = hipe_sparc:alu_src1(I),      Src2 = hipe_sparc:alu_src2(I),      case {hipe_sparc:is_imm(Src1),hipe_sparc:is_imm(Src2),	    is_commutative(hipe_sparc:alu_operator(I))} of	{true,false,true} ->	  I0 = hipe_sparc:alu_src1_update(I, Src2),	  [hipe_sparc:alu_src2_update(I0, Src1)];	{true,_,_} ->	  Tmp = hipe_sparc:mk_new_reg(),	  Mov = hipe_sparc:move_create(Tmp, Src1),	  NewI = hipe_sparc:alu_src1_update(I, Tmp),	  [Mov, NewI];	_ ->	  unchanged      end;    #alu_cc{} ->      Src1 = hipe_sparc:alu_cc_src1(I),      Src2 = hipe_sparc:alu_cc_src2(I),      case {hipe_sparc:is_imm(Src1),hipe_sparc:is_imm(Src2),	    is_commutative(hipe_sparc:alu_cc_operator(I))} of	{true,false,true} ->	  I0 = hipe_sparc:alu_cc_src1_update(I, Src2),	  [hipe_sparc:alu_cc_src2_update(I0, Src1)];	{true,_,_} ->	  Tmp = hipe_sparc:mk_new_reg(),	  Mov = hipe_sparc:move_create(Tmp, Src1),	  NewI = hipe_sparc:alu_cc_src1_update(I, Tmp),	  [Mov, NewI];	_ ->	  unchanged      end;    #load{} ->      Src0 = hipe_sparc:load_src(I),      Off0 = hipe_sparc:load_off(I),      case loadstore_operand(Src0, Off0) of	{Src1, Off1} ->	  [hipe_sparc:load_off_update(hipe_sparc:load_src_update(I, Src1), Off1)];	_NoChange -> unchanged      end;    #store{} ->      Dst0 = hipe_sparc:store_dest(I),      Off0 = hipe_sparc:store_off(I),      Src1 = hipe_sparc:store_src(I),      {I1, Changed} =     	case loadstore_operand(Dst0, Off0) of	  {Dst1, Off1} ->	    {hipe_sparc:store_off_update(hipe_sparc:store_dest_update(I, Dst1), Off1),	     true};	  unchanged ->	    {I, false}	end,      case hipe_sparc:is_imm(Src1) of	true ->	  Tmp = hipe_sparc:mk_new_reg(),	  Mov = hipe_sparc:move_create(Tmp, Src1),	  NewI = hipe_sparc:store_src_update(I1,Tmp),	  [Mov, NewI];	false ->	  if Changed =:= true -> [I1];	     true -> unchanged          end      end;      %% XXX: jmp, jmp_link?    _ -> unchanged  end.loadstore_operand(Opnd1, Opnd2) ->    case hipe_sparc:is_imm(Opnd1) of	true ->	    case hipe_sparc:is_imm(Opnd2) of		true -> 		    Sum = (hipe_sparc:imm_value(Opnd1) + hipe_sparc:imm_value(Opnd2))		          band 16#ffffffff,		    NewOpnd2 = hipe_sparc:mk_imm(Sum),		    NewOpnd1 = hipe_sparc:mk_reg(hipe_sparc_registers:zero()),		    {NewOpnd1, NewOpnd2};		false -> {Opnd2, Opnd1}	    end;	false -> unchanged    end.is_commutative(Op) ->   case Op of      '+' -> true;      'or' -> true;      'and' -> true;      'xor' -> true;      _ -> false   end.split_instr(I) ->   Uses = hipe_sparc:imm_uses(I),   case big_constants(Uses) of      {[], []} -> unchanged;      {Code, Subst} -> [hipe_sparc:subst(I, Subst) | Code]   end.big_constants([]) ->   {[], []};big_constants([V|Vs]) ->   C = hipe_sparc:imm_value(V),   case is_big(C) of      true ->	 NewVar = hipe_sparc:mk_new_reg(),	 Low = low10(C),         Code = 	  if Low =:= 0 ->	      [hipe_sparc:sethi_create(NewVar,				       hipe_sparc:mk_imm(high22(C)))];	    true ->	     	      [hipe_sparc:alu_create(NewVar, NewVar, 'or', 				     hipe_sparc:mk_imm(Low)),	       hipe_sparc:sethi_create(NewVar,				       hipe_sparc:mk_imm(high22(C)))]	  end,	 {MoreCode, MoreSubst} = big_constants(Vs),	 {Code++MoreCode, [{V, NewVar} | MoreSubst]};      false ->	 big_constants(Vs)   end.is_big(X) ->   if X > 4095 ->	 true;      X < -4096 ->	 true;      true ->	 false   end.high22(X) -> X bsr 10.low10(X) -> X band 16#3ff.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?