📄 hipe_sparc_caller_saves.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 + -