⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hipe_sparc_caller_saves.erl

📁 OTP是开放电信平台的简称
💻 ERL
字号:
%% -*- erlang-indent-level: 2 -*-%% ====================================================================%%  Filename : 	hipe_sparc_caller_saves.erl%%  Module   :	hipe_sparc_caller_saves%%  Purpose  :  To add save and restore code for caller save regs%%              at call sites.%%  Notes    :  LastSpillPos is a bad name in this module,%%               since it denotes the postion after the last used%%               position.%%  History  :	* 2001-11-16 Erik Johansson (happi@csd.uu.se): %%               Created.%%  CVS      :%%              $Author: kostis $%%              $Date: 2005/11/06 13:10:51 $%%              $Revision: 1.18 $%% ====================================================================%%  Exports  :%%%%  Description:%%%%   1. Calculate liveness. %%      (Consider reusing the liveness calculated by the regalloc.)%%%%   2. Go through each basic block bottom up.%%      For each call c:%%         For each live out temp t. (that is not a retval of c)%%             If t is spilled: Do nothing.%%             If t is not spilled:%%                a) Get a spillposition p for t.%%                b) Add code for spilling t to p before the call.%%                c) add code for unspilling t from p after the call.%%                d) If any spillcode was added rewrite the call%%                     If there is an exception handler: add the unspill%%                       code to both branches of the call.%%%%   3. Optimization pass: Place the spillcode "optimally".%%                        Implemented in hipe_sparc_opt_frame%%%%  TODO: Either make this module completely target independent or%%        completely target dependent.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-module(hipe_sparc_caller_saves).-export([rewrite/5]).-define(HIPE_INSTRUMENT_COMPILER, true). %% Turn on instrumentation.-include("../main/hipe.hrl").-include("hipe_sparc.hrl").%% XXX: Make target independent.-define(TARGET, hipe_sparc_specific).%% XXX: Make target independent.rewrite(Cfg, TempMap, FpMap, LastSpillPos, Options) ->  %% hipe_sparc_cfg:pp(Cfg),    ?opt_start_timer("Caller Saves"),  ?start_time_caller_saves(Options),  %% Get Info.  Liveness = liveness(Cfg, ?TARGET),  State = new_state(Liveness,  Cfg, TempMap, FpMap, LastSpillPos),  BBs = hipe_sparc_cfg:predictionorder(Cfg),  %% Rewrite.  {NewCode, NextPos, NewBlocks} = traverse(BBs, State),  %% Make new CFG.  Sparc0 = hipe_sparc_cfg:linearize(Cfg),  Sparc1 = hipe_sparc:sparc_code_update(Sparc0, NewCode),  Sparc2 = hipe_sparc:sparc_var_range_update(	     Sparc1, {0,hipe_gensym:get_var(sparc)}),  Sparc3 = hipe_sparc:sparc_label_range_update(	     Sparc2, {0,hipe_gensym:get_label(sparc)}),    Cfg1 = hipe_sparc_cfg:init(Sparc3),  %% Minimize the number of loads and stores.  ?opt_stop_timer("Caller Saves"),  ?opt_start_timer("Opt Frame"),  %% hipe_sparc_cfg:pp(Cfg1),  Cfg2 = hipe_sparc_opt_frame:cfg(Cfg1),  %% hipe_sparc_cfg:pp(Cfg2),  ?opt_stop_timer("Opt Frame"),  ?stop_time_caller_saves(Options),  case proplists:get_value(regalloc,Options) of    cs ->      {Cfg2, NextPos, NewBlocks};    _ ->      {Cfg2, NextPos}  end.%% Go through each BasicBlocktraverse(BBs, State) ->  State1 = lists:foldr(fun handle_bb/2,State,BBs),    {state__instrs(State1),state__spill_index(State1),state__newblocks(State1)}.  %% For each BasicBlock go through the code bottom-up.handle_bb(BB,State) ->  %% io:format("--------------\n",[]),  Code =  hipe_bb:code(bb(state__cfg(State),BB, ?TARGET)),  State1 = state__enter_bb(BB, State),  State2 = bottom_up(Code, State1),  %% io:format("-- Block ~w --\n",[BB]),  state__add_instrs(hipe_sparc:label_create(BB), State2).%% Go through each instruction from the last to the first.%% (Collect liveness from live out and backwards.)bottom_up(Is, State) ->  lists:foldr(fun handle/2,State,Is).%% For each instruction rewrite calls so that live temps are savedhandle(I,State) ->  {FpDefs, Defs}  = defines(I, ?TARGET),  {FpUses, Uses} = uses(I, ?TARGET),  LiveOut = state__live(State)-- hipe_sparc_registers:global(),  Live = (LiveOut--Defs), %% Remove killed  LiveIn = ordsets:union(ordsets:from_list(Live),ordsets:from_list(Uses))    -- hipe_sparc_registers:global(),  FpLiveOut = state__live_fp(State),  FpLive = (FpLiveOut--FpDefs), %% Remove killed  FpLiveIn = ordsets:union(ordsets:from_list(FpLive),ordsets:from_list(FpUses)),    %% io:format("~nLiveOut: ~w~n",[LiveOut-- hipe_sparc_registers:global()]),    %% hipe_sparc_pp:pp_instr(I),    %% io:format("LiveIn: ~w~n",[LiveIn]),  %% Add save and restores if neccessary.  State1 = update_call(I,State,Live, LiveOut, FpLive),  %% Update the liveness information in the state.  State2 = state__update_live(LiveIn, State1),  state__update_live_fp(FpLiveIn, State2).%% XXX: Make this target independent.update_call(I,State,Live,_LiveOut,FpLive) ->  case I of    #call_link{} ->      case {live_in_regs(Live), FpLive} of	{[], []} -> 	  %% All live temps are allready on the stack.	  %% No need for extra saving.	  %% Just add the live-info to the stack descriptor 	  %%  of the call.	  state__add_instrs(set_live_slots(I,State,Live),State);	{ToSpill, ToSpillFp} ->	  %% We have at least one live temp that is not on the stack	  handle_call(I,State,ToSpill,Live, ToSpillFp)      end;        _ ->      %% This is not a call, nothing to save.      %% Just add the instruction to the state.      state__add_instrs(I,State)  end.%% Ugly function that finds the stack slots of all live temps%% and adds these to the stack descriptor of the call. set_live_slots(Call,State,LiveOut) ->  Live =    [stack_pos(T,State, reg) || T <- LiveOut],  SD = hipe_sparc:call_link_stack_desc(Call),  NewSD = hipe_sparc:sdesc_live_slots_update(SD, Live),  hipe_sparc:call_link_stack_desc_update(Call,NewSD).%% Helper function to set_live_slots.%% Maps a Temp to its stack pos.stack_pos(T,State, Type) ->  Map =     case Type of      reg -> state__tempmap(State);      fp_reg-> state__fpmap(State)    end,  case hipe_temp_map:find(T, Map) of    {spill, P} ->      P;    _ ->      element(1,get_pos(T,state__extramap(State), Type))  end.      %% XXX: Make target independent.live_in_regs(Live) ->  %% XXX: We have to save spilled regs with new call-split allocation  %%      Make this modular so other allocators are unaffected.  [T || T <- Live ]     -- hipe_sparc_registers:global().handle_call(I,State,ToSpill,LiveOut, FpLive)->  %% a) Get a spillposition p for t.  %% b) Add code for spilling t to p before the call.  %% c) add code for unspilling t from p after the call.  %% d) If any spillcode was added rewrite the call  %%      If there is an exception handler: add the unspill  %%        code to both branches of the call.  ExtraMap = state__extramap(State),  {SpillPositions, NewExtraMap0} =    get_spill_positions(ToSpill, ExtraMap, State, reg),  {Saves0, Restores0} = gen_save_restore(SpillPositions, reg),  {SpillPositions_fp, NewExtraMap} =    get_spill_positions(FpLive, NewExtraMap0, State, fp_reg),  {Saves1, Restores1} = gen_save_restore(SpillPositions_fp, fp_reg),  State1 = state__update_extramap(NewExtraMap, State),  ContLab = hipe_sparc:call_link_continuation(I),  FailLab = hipe_sparc:call_link_fail(I),  NewContLab = hipe_sparc:label_create_new(),  GotoCont =  hipe_sparc:goto_create(ContLab),  {NewI,State2} =    case ContLab of      [] -> {I, State1};      _ ->	{	hipe_sparc:call_link_continuation_update(	  I,	  hipe_sparc:label_name(NewContLab)),	state__add_block(hipe_sparc:label_name(NewContLab),ContLab, State1)}    end,     %% Update stack descriptor. Fp regs must not be marked as live.  NewCall = set_live_slots(NewI,State2,LiveOut),  case ContLab of    [] ->       NewCode = 	[Saves0,	 Saves1,	 NewCall,	 Restores0,	 Restores1],      state__add_instrs(NewCode,State2);    _ ->      case FailLab of	[] ->	  NewCode = 	    [Saves0,	     Saves1,	     NewCall,	     NewContLab,	     Restores0,	     Restores1,	     GotoCont],	  state__add_instrs(NewCode,State2);	_ ->	  NewFailLab = hipe_sparc:label_create_new(),	  GotoFail =  hipe_sparc:goto_create(FailLab),	  NewI2 = 	    hipe_sparc:call_link_fail_update(	      NewCall,	      hipe_sparc:label_name(NewFailLab)),	  State3 = 	    state__add_block(hipe_sparc:label_name(NewFailLab),FailLab, State2),	  NewCode = 	    [Saves0, 	     Saves1,	     NewI2,	     NewContLab,	     Restores0,	     Restores1,	     GotoCont,	     NewFailLab,	     Restores0,	     Restores1,	     GotoFail],	  state__add_instrs(NewCode,State3)      end  end.get_spill_positions([T|Temps], ExtraMap, State, Type) ->  TempMap =     case Type of      reg -> state__tempmap(State);      fp_reg -> state__fpmap(State)    end,  {Pos, NewMap} =     case hipe_temp_map:is_spilled(T, TempMap) of      true ->	{stack_pos(T, State, Type),ExtraMap};      false ->	get_pos(T,ExtraMap, Type)    end,  {Positions, Map} = get_spill_positions(Temps, NewMap, State, Type),  {[{T,Pos}|Positions], Map};get_spill_positions([],Map,_, _) ->  {[],Map}.gen_save_restore([{T,Pos}|Positions], Type) ->  SparcTemp =     case Type of      fp_reg -> hipe_sparc:mk_fpreg(T);      reg -> hipe_sparc:mk_reg(T)    end,  SparcPos = hipe_sparc:mk_imm(Pos),  {Saves, Restores} = gen_save_restore(Positions, Type),  Save = hipe_sparc:pseudo_spill_create(SparcTemp,SparcPos),  Restore = hipe_sparc:pseudo_unspill_create(SparcTemp,SparcPos),  {[Save | Saves], [Restore | Restores]};gen_save_restore([], _) -> {[],[]}.%% ================================================================= %%%%                             A  D  T s                             %%%% ================================================================= %%%% ================================================================= %%%% The ExtraMap structure%% Maps unspilled temps to spillpositions.%% %% ____________________________________________________________________%%  new_extramap(LastSpillPos)    %% Returns: 	An empty ExtraMap.%% Arguments:	LastSpillPos - The next spill will be to this pos.%% Description:	Creates an empty ExtraMap %% ____________________________________________________________________new_extramap(LastSpillPos) ->  {LastSpillPos, empty()}.index(Map) ->  %% io:format("Map: ~w\n",[Map]),  element(1,Map).%% ____________________________________________________________________%%  get_pos(T,ExtraMap, Type)    %% Returns: 	%% Arguments:	%% Description:	Finds the spill position of the temp T,%%              If T is not in the map T will be added. %%              Type is either reg or fp_reg %% ____________________________________________________________________get_pos(T,{Next,Map}, Type) ->  case lookup(T,Map) of    none ->      case Type of	fp_reg -> {Next, {Next+2,insert(T,Next,Map)}};	reg -> {Next, {Next+1,insert(T,Next,Map)}}      end;    {value, Pos} ->      {Pos, {Next,Map}}  end.%% ____________________________________________________________________%% %% The Map kernel.empty() ->  gb_trees:empty().lookup(T,Map) ->  gb_trees:lookup(T,Map).insert(T,Next,Map) ->  gb_trees:insert(T,Next,Map).%% ================================================================= %%%%%% The state structure%%%% ================================================================= %%%% ____________________________________________________________________%% The state record.-record(state, {instrs, extramap, live, live_fp, liveness, cfg, tempmap, fpmap, newblocks}).%% Create a new state.new_state(Liveness,  Cfg, TempMap, FpMap, LastSpillPos) ->  #state{instrs = [], 	 extramap = new_extramap(LastSpillPos), 	 live = [],	 live_fp = [],	 liveness = Liveness,  	 cfg = Cfg,	 tempmap = TempMap,	 fpmap = FpMap,	 newblocks = []}.%% ____________________________________________________________________%% Selectorsstate__instrs(#state{instrs=Instrs}) -> lists:flatten(Instrs).state__extramap(#state{extramap=ExtraMap}) -> ExtraMap.state__live(#state{live=Live}) -> Live.state__live_fp(#state{live_fp=LiveFP}) -> LiveFP.state__liveness(#state{liveness=Liveness}) -> Liveness.state__cfg(#state{cfg=CFG}) -> CFG.state__tempmap(#state{tempmap=TempMap}) -> TempMap.state__fpmap(#state{fpmap=FpMap}) -> FpMap.state__newblocks(#state{newblocks=NewBlocks}) -> NewBlocks.state__spill_index(State) -> index(state__extramap(State)).%% ____________________________________________________________________%% Updatesstate__enter_bb(BB, State) ->  {FpReg, Reg} = liveout(state__liveness(State), BB, hipe_sparc_specific),  State#state{live=ordsets:from_list(Reg), live_fp=ordsets:from_list(FpReg)}.state__add_instrs(I,State) ->  State#state{instrs=[I|state__instrs(State)]}.state__update_extramap(NewExtraMap, State) ->  State#state{extramap=NewExtraMap}.state__update_live(NewLive, State) ->  State#state{live=NewLive}.state__update_live_fp(NewLive, State) ->  State#state{live_fp=NewLive}.state__add_block(New,Old, State) ->   State#state{newblocks=[{New,Old}|state__newblocks(State)]}.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Interface to target specific external functions.%% XXX: Make this efficient somehow...%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%liveness(CFG, Target) ->   Target:analyze(CFG).bb(CFG, L, Target) ->  Target:bb(CFG,L).liveout(Liveness,L, Target)->  regnames(Target:liveout(Liveness,L), Target).uses(I, Target)->  regnames(Target:uses(I), Target).defines(I, Target) ->  regnames(Target:defines(I), Target).regnames(Regs, _Target) ->  regnames(Regs, [], []).regnames([Reg|Rest], Fp_regs, Regs) ->  case hipe_sparc:is_fpreg(Reg) of    true->      regnames(Rest, [hipe_sparc:fpreg_nr(Reg) | Fp_regs], Regs);    _ ->      regnames(Rest, Fp_regs, [hipe_sparc:reg_nr(Reg) | Regs])  end;regnames([], Fp_regs, Regs) ->  {Fp_regs, Regs}.  

⌨️ 快捷键说明

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