%% -*- erlang-indent-level: 2 -*- %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% File : hipe_rtl_ssapre.erl %% Author : He Bingwen and Frédéric Haziza %% Description : Performs Partial Redundancy Elimination on SSA form. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% @doc %% %% This module implements the Anticipation-SSAPRE algorithm, %% with several modifications for Partial Redundancy Elimination on SSA form. %% We actually found problems in this algorithm, so %% we implement another version with several advantages: %% - No loop for Xsi insertions %% - No fix point iteration for the downsafety part %% - Less computations for Will Be Available part %% - Complexity of the overall algorithm is improved %% %% We were supposed to publish these results anyway :D %% %% @end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -module(hipe_rtl_ssapre). -export([rtl_ssapre/2]). -include("../main/hipe.hrl"). -include("hipe_rtl.hrl"). %%-define(SSAPRE_DEBUG, true ). %% When uncommented, produces debug printouts -define( SETS, ordsets ). %% Which set implementation module to use -define( CFG, hipe_rtl_cfg ). -define( RTL, hipe_rtl ). -define( BB, hipe_bb ). -define( ARCH, hipe_rtl_arch ). -define( GRAPH, digraph ). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Debugging stuff %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -ifndef(SSAPRE_DEBUG). -define(pp_debug(_Str, _Args), ok). -else. -define(pp_debug(Str, Args), io:format(standard_io, Str, Args)). -endif. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Records / Structures %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -record(xsi_link, {num}). %% Number is the index of the temporary (a Key into the Xsi Tree) -record(temp, {key, var}). -record(bottom, {key, var}). -record(xsi, {inst, %% Associated instruction def, %% Hypothetical temporary variable %% that stores the result of the computation label, %% Block Label where the xsi is inserted opList, %% List of operands cba, %% later, %% wba }). -record(pre_candidate, {alu, def}). -record(xsi_op, {pred, op}). -record(mp, {xsis, maps, preds, defs, uses, ndsSet}). -record(block, {type, attributes}). -record(eop, {expr, var, stopped_by}). -record(insertion, {code, from}). -record(const_expr, {var, value}). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Main function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% rtl_ssapre(RtlSSACfg, Options) -> %% io:format("\n################ Original CFG ################\n"), %% hipe_rtl_cfg:pp(RtlSSACfg), %% io:format("\n\n############ SSA-Form CHECK ==> ~w\n",[hipe_rtl_ssa:check(RtlSSACfg)]), {CFG2,XsiGraph,CFGGraph,MPs} = perform_Xsi_insertion(RtlSSACfg,Options), %%?pp_debug("~n~n################ Xsi CFG ################\n",[]),pp_cfg(CFG2,XsiGraph), XsiList = ?GRAPH:vertices(XsiGraph), case XsiList of [] -> %% No Xsi ?pp_debug("~n~n################ No Xsi Inserted ################~n",[]), ok; _ -> ?pp_debug("~n############ Downsafety ##########~n",[]), ?option_time(perform_downsafety(MPs,CFGGraph,XsiGraph),"RTL A-SSAPRE Downsafety",Options), ?pp_debug("~n~n################ CFG Graph ################~n",[]),pp_cfggraph(CFGGraph), ?pp_debug("~n############ Will Be Available ##########~n",[]), ?option_time(perform_will_be_available(XsiGraph,CFGGraph,Options),"RTL A-SSAPRE WillBeAvailable",Options) end, ?pp_debug("~n############ No more need for the CFG Graph....Deleting...",[]),?GRAPH:delete(CFGGraph), ?pp_debug("~n~n################ Xsi Graph ################~n",[]),pp_xsigraph(XsiGraph), ?pp_debug("~n############ Code Motion ##########~n",[]), Labels = ?CFG:preorder(CFG2), ?pp_debug("~n~n################ Xsi CFG ################~n",[]),pp_cfg(CFG2,XsiGraph), init_redundancy_count(), FinalCFG = ?option_time(perform_code_motion(Labels,CFG2,XsiGraph),"RTL A-SSAPRE Code Motion",Options), ?pp_debug("\n############ No more need for the Xsi Graph....Deleting...",[]),?GRAPH:delete(XsiGraph), %% io:format("\n################ Final CFG ################\n"), %% hipe_rtl_cfg:pp(FinalCFG), %% io:format("\n\n############ SSA-Form CHECK ==> ~w\n", %% [hipe_rtl_ssa:check(FinalCFG)]), ?pp_debug("\nSSAPRE : ~w redundancies were found\n",[get_redundancy_count()]), FinalCFG. %% ########################################################################## %% ######################## XSI INSERTION ################################### %% ########################################################################## perform_Xsi_insertion(Cfg, Options) -> init_counters(), %% Init counters for Bottoms and Temps DigraphOpts = [cyclic, private], XsiGraph = digraph:new(DigraphOpts), %% Be careful, the digraph component is NOT garbage collected, %% so don't create 20 millions of instances! %% finds the longest depth %% Depth-first, preorder traversal over Basic Blocks. %%Labels = ?CFG:reverse_postorder(Cfg), Labels = ?CFG:preorder(Cfg), ?pp_debug("~n~n############# Finding definitions for computation~n~n",[]), {Cfg2,XsiGraph} = ?option_time(find_definition_for_computations(Labels,Cfg,XsiGraph),"RTL A-SSAPRE Xsi Insertion, searching from instructions",Options), %% Active List creation GeneratorXsiList = lists:sort(?GRAPH:vertices(XsiGraph)), ?pp_debug("~n~n############# Inserted Xsis ~w",[GeneratorXsiList]), ?pp_debug("~n~n############# Finding operands~n",[]), {Cfg3,XsiGraph} = ?option_time(find_operands(Cfg2,XsiGraph,GeneratorXsiList,0),"RTL A-SSAPRE Xsi Insertion, finding operands",Options), %% Creating the CFGGraph ?pp_debug("~n~n############# Creating CFG Graph",[]), ?pp_debug("~n############# Labels = ~w",[Labels]), CFGGraph = digraph:new(DigraphOpts), [StartLabel|Others] = Labels, % adding the start label as a leaf ?pp_debug("~nAdding a vertex for the start label: ~w",[StartLabel]), ?GRAPH:add_vertex(CFGGraph, StartLabel, #block{type = top}), % Doing the others MPs = ?option_time(create_cfggraph(Others,Cfg3,CFGGraph,[],[],[],XsiGraph),"RTL A-SSAPRE Xsi Insertion, creating intermediate 'SSAPRE Graph'",Options), %% Return the collected information {Cfg3,XsiGraph,CFGGraph,MPs}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% find_definition_for_computations([], Cfg, XsiGraph) -> {Cfg,XsiGraph}; %% No more block to inspect in the depth-first order find_definition_for_computations([Label|Rest], Cfg, XsiGraph) -> Code = ?BB:code(?CFG:bb(Cfg,Label)), {NewCfg,XsiGraph} = find_definition_for_computations_in_block(Label,Code,Cfg,[],XsiGraph), find_definition_for_computations(Rest, NewCfg, XsiGraph). %%=========================================================================== %% Searches from instruction for one block BlockLabel. %% We process forward over instructions. find_definition_for_computations_in_block(BlockLabel,[],Cfg, VisitedInstructions,XsiGraph)-> Code = lists:reverse(VisitedInstructions), NewBB = ?BB:mk_bb(Code), NewCfg = ?CFG:bb_add(Cfg,BlockLabel,NewBB), {NewCfg,XsiGraph}; %% No more instructions to inspect in this block find_definition_for_computations_in_block(BlockLabel,[Inst|Rest],Cfg, VisitedInstructions,XsiGraph) -> %% ?pp_debug(" Inspecting instruction: ",[]),pp_instr(Inst,nil), case Inst of #alu{} -> %% Is Inst interesting for SSAPRE? %% i.e., is Inst an arithmetic operation which doesn't deal with precoloured? %% Note that since we parse forward, we have no 'pre_candidate'-type so far. case check_definition(Inst,VisitedInstructions,BlockLabel,Cfg,XsiGraph) of {def_found,Def} -> %% Replacing Inst in Cfg NewInst = #pre_candidate{alu=Inst,def=Def}, NewVisited = [NewInst|VisitedInstructions], %% Recurse forward over instructions, same CFG, same XsiGraph find_definition_for_computations_in_block(BlockLabel,Rest,Cfg, NewVisited,XsiGraph); {merge_point,Xsi} -> Def = Xsi#xsi.def, Key = Def#temp.key, NewInst = #pre_candidate{alu=Inst,def=Def}, XsiLink = #xsi_link{num=Key}, %% Add a vertex to the Xsi Graph ?GRAPH:add_vertex(XsiGraph,Key,Xsi), ?pp_debug(" Inserting Xsi: ",[]),pp_xsi(Xsi), Label = Xsi#xsi.label, {NewCfg, NewVisited} = case BlockLabel =:= Label of false -> %% Insert the Xsi in the appropriate block Code = hipe_bb:code(?CFG:bb(Cfg,Label)), {BeforeCode,AfterCode} = split_for_xsi(lists:reverse(Code),[]), NewCode = BeforeCode++[XsiLink|AfterCode], NewBB = hipe_bb:mk_bb(NewCode), {?CFG:bb_add(Cfg,Label,NewBB), [NewInst|VisitedInstructions]}; _-> {BeforeCode,AfterCode} = split_for_xsi(VisitedInstructions,[]), TempVisited = BeforeCode++[XsiLink|AfterCode], TempVisited2 = lists:reverse(TempVisited), {Cfg, [NewInst|TempVisited2]} end, find_definition_for_computations_in_block(BlockLabel, Rest, NewCfg, NewVisited, XsiGraph) end; _ -> %%?pp_debug("~n [L~w] Not concerned with: ~w",[BlockLabel,Inst]), %% If the instruction is not a SSAPRE candidate, we skip it and keep on %% processing instructions %% Prepend Inst, so that we have all in reverse order. %% Easy to parse backwards find_definition_for_computations_in_block(BlockLabel, Rest, Cfg, [Inst|VisitedInstructions], XsiGraph) end. %% ############################################################################ %% We have E as an expression, I has an alu (arithmetic operation), and %% we inspect backwards the previous instructions to find a definition for E. %% Since we parse in forward order, we know that the previous SSAPRE %% instruction will have a definition. check_definition(E,[],BlockLabel,Cfg,XsiGraph)-> %% No more instructions in that block %% No definition found in that block %% Search is previous blocks Preds = ?CFG:pred(Cfg, BlockLabel), %% ?pp_debug("~n CHECKING DEFINITION ####### Is L~w a merge block? It has ~w preds. So far E=",[BlockLabel,length(Preds)]),pp_expr(E), case Preds of [] -> %% Entry Point {def_found,bottom}; [P] -> %% One predecessor only, we just keep looking for a definition in that block VisitedInstructions = lists:reverse(hipe_bb:code(?CFG:bb(Cfg,P))), check_definition(E,VisitedInstructions,P,Cfg,XsiGraph); _ -> Temp = new_temp(), %% It's a merge point OpList = [#xsi_op{pred=X} || X<-Preds], Xsi = #xsi{inst=E,def=Temp,label=BlockLabel,opList=OpList}, {merge_point,Xsi} end; check_definition(E,[CC|Rest],BlockLabel,Cfg,XsiGraph) -> SRC1 = ?RTL:alu_src1(E), SRC2 = ?RTL:alu_src2(E), case CC of #alu{} -> exit({?MODULE,should_not_be_an_alu, {"Why the hell do we still have an alu???",CC}}); #pre_candidate{} -> %% C is the previous instruction C = CC#pre_candidate.alu, DST = ?RTL:alu_dst(C), case DST =:= SRC1 orelse DST =:= SRC2 of false -> case check_match(E,C) of true -> %% It's a computation of E! %% Get the dst of the alu {def_found,DST}; _-> check_definition(E,Rest,BlockLabel,Cfg,XsiGraph) end; true -> %% Get the definition of C, since C is PRE-candidate AND has been processed before DEF = CC#pre_candidate.def, case DEF of bottom -> %% Def(E)=bottom, STOP {def_found,bottom}; _ -> %% Emend E with this def(C) %%?pp_debug("Parameters are E=~w, DST=~w, DEF=~w",[E,DST,DEF]), F = emend(E,DST,DEF), check_definition(F,Rest,BlockLabel,Cfg,XsiGraph) %% Continue the search end end; #move{} -> %% It's a move, we emend E, and continue the definition search DST = ?RTL:move_dst(CC), F = case SRC1 =:= DST orelse SRC2 =:= DST of true -> SRC = ?RTL:move_src(CC), emend(E,DST,SRC); _ -> E end, check_definition(F,Rest,BlockLabel,Cfg,XsiGraph); %% Continue the search #xsi_link{} -> {_K,Xsi} = ?GRAPH:vertex(XsiGraph,CC#xsi_link.num), C = Xsi#xsi.inst, case check_match(C,E) of true -> %% There is a Xsi already with a computation of E! %% fetch definition of C, and give it to E {def_found,Xsi#xsi.def}; _-> check_definition(E,Rest,BlockLabel,Cfg,XsiGraph) end; #phi{} -> %% skip them. NOTE: Important to separate this case from the next one check_definition(E,Rest,BlockLabel,Cfg,XsiGraph); _ -> %% Note: the function calls or some other instructions can change the pre-coloured registers %% which are able to be redefined. This breaks of course the SSA form. %% If there is a redefinition we can give bottom to the computation, and no xsi will be inserted. %% (In some sens, the result of the computation is new at that point.) PreColouredTest = ?ARCH:is_precoloured(SRC1) orelse ?ARCH:is_precoloured(SRC2), %%RegisterTest = ?RTL:is_reg(?RTL:alu_dst(E)) orelse ?RTL:is_reg(SRC1) orelse ?RTL:is_reg(SRC2), RegisterTest = ?RTL:is_reg(?RTL:alu_dst(E)), %% That means we cannot reuse the result held in this register... case PreColouredTest orelse RegisterTest of true -> {def_found,bottom}; false -> DC = ?RTL:defines(CC), case lists:member(SRC1,DC) orelse lists:member(SRC2,DC) of true -> {def_found,bottom}; false -> %% Orthogonal to E, we continue the search check_definition(E,Rest,BlockLabel,Cfg,XsiGraph) end end end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% check_match(E, C) -> OpE = ?RTL:alu_op(E), OpC = ?RTL:alu_op(C), case OpE =:= OpC of false -> false; true -> Src1E = ?RTL:alu_src1(E), Src2E = ?RTL:alu_src2(E), Src1C = ?RTL:alu_src1(C), Src2C = ?RTL:alu_src2(C), case Src1E =:= Src1C of true -> Src2E =:= Src2C; false -> Src1E =:= Src2C andalso Src2E =:= Src1C end end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% expr_is_const(E) -> ?RTL:is_imm(?RTL:alu_src1(E)) andalso ?RTL:is_imm(?RTL:alu_src2(E)). %% is_number(?RTL:alu_src1(E)) andalso is_number(?RTL:alu_src2(E)). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Must be an arithmetic operation, i.e. #alu{} emend(Expr, S, Var) -> SRC1 = ?RTL:alu_src1(Expr), NewExpr = case SRC1 =:= S of true -> ?RTL:alu_src1_update(Expr,Var); false -> Expr end, SRC2 = ?RTL:alu_src2(NewExpr), case SRC2 =:= S of true -> ?RTL:alu_src2_update(NewExpr,Var); false -> NewExpr end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% split_for_xsi([], Acc) -> {[], Acc}; % no_xsi_no_phi_found; split_for_xsi([I|Is] = Code, Acc) -> %% [I|Is] in backward order, Acc in order case I of #xsi_link{} -> {lists:reverse(Code), Acc}; #phi{} -> {lists:reverse(Code), Acc}; _ -> split_for_xsi(Is, [I|Acc]) end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Phase 1.B : Search for operands %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% find_operands(Cfg,XsiGraph,[],_Count) -> {Cfg,XsiGraph}; find_operands(Cfg,XsiGraph,ActiveList,Count) -> {NewCfg,TempActiveList} = find_operands_for_active_list(Cfg,XsiGraph,ActiveList,[]), NewActiveList = lists:reverse(TempActiveList), ?pp_debug("~n################ Finding operands (iteration ~w): ~w have been introduced. Now ~w in total~n", [Count+1, length(NewActiveList), length(?GRAPH:vertices(XsiGraph))]), find_operands(NewCfg,XsiGraph,NewActiveList,Count+1). find_operands_for_active_list(Cfg,_XsiGraph,[],ActiveListAcc) -> {Cfg,ActiveListAcc}; find_operands_for_active_list(Cfg,XsiGraph,[K|Ks],ActiveListAcc) -> {_Key,Xsi} = ?GRAPH:vertex(XsiGraph,K), ?pp_debug("~n Inspecting operands of : ~n",[]),pp_xsi(Xsi), Preds = ?CFG:pred(Cfg, Xsi#xsi.label), {NewCfg,NewActiveListAcc}=determine_operands(Xsi,Preds,Cfg,K,XsiGraph,ActiveListAcc), {_Key2,Xsi2} = ?GRAPH:vertex(XsiGraph,K), ?pp_debug("~n ** Final Xsi: ~n",[]),pp_xsi(Xsi2), ?pp_debug("~n #####################################################~n",[]), find_operands_for_active_list(NewCfg,XsiGraph,Ks,NewActiveListAcc). determine_operands(_Xsi,[],Cfg,_K,_XsiGraph,ActiveAcc) -> %% All operands have been determined. %% The CFG is not updated, only the XsiGraph {Cfg,ActiveAcc}; determine_operands(Xsi,[P|Ps],Cfg,K,XsiGraph,ActiveAcc) -> Label = Xsi#xsi.label, ReverseCode = lists:reverse(hipe_bb:code(?CFG:bb(Cfg,Label))), VisitedInstructions = get_visited_instructions(Xsi,ReverseCode), Res = determine_e_prime(Xsi#xsi.inst,VisitedInstructions,P,XsiGraph), case Res of operand_is_bottom -> NewXsi = xsi_arg_update(Xsi,P,new_bottom()), ?GRAPH:add_vertex(XsiGraph,K,NewXsi), determine_operands(NewXsi,Ps,Cfg,K,XsiGraph,ActiveAcc); operand_is_const_expr -> NewXsi = xsi_arg_update(Xsi,P,new_bottom()), ?GRAPH:add_vertex(XsiGraph,K,NewXsi), determine_operands(NewXsi,Ps,Cfg,K,XsiGraph,ActiveAcc); {sharing_operand,Op} -> NewXsi = xsi_arg_update(Xsi,P,Op), ?GRAPH:add_vertex(XsiGraph,K,NewXsi), determine_operands(NewXsi,Ps,Cfg,K,XsiGraph,ActiveAcc); {revised_expression,E_prime} -> ?pp_debug(" E' is determined : ",[]),pp_expr(E_prime), ?pp_debug(" and going along the edge L~w~n",[P]), %% Go along the edge P RevCode = lists:reverse(hipe_bb:code(?CFG:bb(Cfg,P))), case check_one_operand(E_prime,RevCode,P,Cfg,K,XsiGraph) of {def_found,Def} -> NewXsi = xsi_arg_update(Xsi,P,Def), ?GRAPH:add_vertex(XsiGraph,K,NewXsi), determine_operands(NewXsi,Ps,Cfg,K,XsiGraph,ActiveAcc); {expr_found,ChildExpr} -> NewXsi = xsi_arg_update(Xsi,P,ChildExpr), ?GRAPH:add_vertex(XsiGraph,K,NewXsi), determine_operands(NewXsi,Ps,Cfg,K,XsiGraph,ActiveAcc); {expr_is_const, Op} -> %% We detected that the expression is of the form: 'N op M' %% where N and M are constant. NewXsi = xsi_arg_update(Xsi,P,Op), ?GRAPH:add_vertex(XsiGraph,K,NewXsi), determine_operands(NewXsi,Ps,Cfg,K,XsiGraph,ActiveAcc); {merge_point,XsiChild} -> %% Update that Xsi, give its definition as Operand for the %% search, and go on XsiChildDef = XsiChild#xsi.def, NewXsi = xsi_arg_update(Xsi,P,XsiChildDef), ?GRAPH:add_vertex(XsiGraph,K,NewXsi), KeyChild = XsiChildDef#temp.key, XsiChildLink = #xsi_link{num=KeyChild}, ?GRAPH:add_vertex(XsiGraph,KeyChild,XsiChild), %% Should not be the same block !!!!!!! RCode = lists:reverse(hipe_bb:code(?CFG:bb(Cfg,XsiChild#xsi.label))), {BCode,ACode} = split_code_for_xsi(RCode,[]), NewCode = BCode++[XsiChildLink|ACode], NewBB = hipe_bb:mk_bb(NewCode), NewCfg = ?CFG:bb_add(Cfg, XsiChild#xsi.label, NewBB), ?pp_debug(" -- ",[]),pp_arg(Xsi#xsi.def),?pp_debug(" causes insertion of: ~n",[]),pp_xsi(XsiChild), ?pp_debug(" -- Adding an edge ",[]),pp_arg(Xsi#xsi.def),?pp_debug(" -> ",[]),pp_arg(XsiChild#xsi.def), %% Adding an edge... %%?GRAPH:add_edge(XsiGraph,K,KeyChild,"family"), ?GRAPH:add_edge(XsiGraph,K,KeyChild), determine_operands(NewXsi,Ps,NewCfg,K,XsiGraph,[KeyChild|ActiveAcc]) end end. determine_e_prime(Expr,VisitedInstructions,Pred,XsiGraph) -> %% MUST FETCH FROM THE XSI TREE, since Xsis are not updated yet in the CFG NewExpr = emend_with_phis(Expr,VisitedInstructions,Pred), emend_with_processed_xsis(NewExpr,VisitedInstructions,Pred,XsiGraph). emend_with_phis(EmendedE, [], _) -> EmendedE; emend_with_phis(E, [I|Rest], Pred) -> case I of #phi{} -> Dst = ?RTL:phi_dst(I), UE = ?RTL:uses(E), %% Should we get SRC1 and SRC2 instead? case lists:member(Dst, UE) of false -> emend_with_phis(E, Rest, Pred); true -> NewE = emend(E, Dst, ?RTL:phi_arg(I,Pred)), emend_with_phis(NewE, Rest, Pred) end; _ -> emend_with_phis(E, Rest, Pred) end. emend_with_processed_xsis(EmendedE, [], _, _) -> {revised_expression,EmendedE}; emend_with_processed_xsis(E, [I|Rest], Pred, XsiGraph) -> case I of #xsi_link{} -> Key = I#xsi_link.num, {_KK,Xsi} = ?GRAPH:vertex(XsiGraph,Key), Def = Xsi#xsi.def, UE = ?RTL:uses(E), %% Should we get SRC1 and SRC2 instead? case lists:member(Def,UE) of false -> CE = Xsi#xsi.inst, case check_match(E,CE) of true -> %% It's a computation of E! case xsi_arg(Xsi,Pred) of undetermined_operand -> exit({?MODULE,check_operand_sharing,"######## Ôh Dear, we trusted Kostis !!!!!!!!! #############"}); XsiOp -> {sharing_operand,XsiOp} %% They share operands end; _-> emend_with_processed_xsis(E,Rest,Pred,XsiGraph) end; true -> A = xsi_arg(Xsi,Pred), %% ?pp_debug(" ######### xsi_arg(I:~w,Pred:~w) = ~w~n",[I,Pred,A]), case A of #bottom{} -> operand_is_bottom; #const_expr{} -> operand_is_const_expr; #eop{} -> NewE = emend(E,Def,A#eop.var), emend_with_processed_xsis(NewE,Rest,Pred,XsiGraph); undetermined_operand -> exit({?MODULE,emend_with_processed_xsis,"######## Ôh Dear, we trusted Kostis, again !!!!!!!!! #############"}); XsiOp -> NewE = emend(E,Def,XsiOp), emend_with_processed_xsis(NewE,Rest,Pred,XsiGraph) end end; _ -> emend_with_processed_xsis(E,Rest,Pred,XsiGraph) end. %% get_visited_instructions(Xsi,[]) -> %% ?pp_debug("~nWe don't find this xsi with def ",[]),pp_arg(Xsi#xsi.def),?pp_debug(" in L~w : ",[Xsi#xsi.label]), %% exit({?MODULE,no_such_xsi_in_block,"We didn't find that Xsi in the block"}); get_visited_instructions(Xsi, [I|Is]) -> case I of #xsi_link{} -> XsiDef = Xsi#xsi.def, Key = XsiDef#temp.key, case I#xsi_link.num =:= Key of true -> Is; false -> get_visited_instructions(Xsi, Is) end; _ -> get_visited_instructions(Xsi, Is) end. split_code_for_xsi([], Acc) -> {[],Acc}; split_code_for_xsi([I|Is] = Code, Acc) -> case I of #xsi_link{} -> {lists:reverse(Code), Acc}; #phi{} -> {lists:reverse(Code), Acc}; _ -> split_code_for_xsi(Is, [I|Acc]) end. check_one_operand(E, [], BlockLabel, Cfg, XsiKey, XsiGraph) -> %% No more instructions in that block %% No definition found in that block %% Search is previous blocks Preds = ?CFG:pred(Cfg, BlockLabel), case Preds of [] -> %% Entry Point {def_found,new_bottom()}; [P] -> %% One predecessor only, we just keep looking for a definition in that block case expr_is_const(E) of true -> ?pp_debug("\n\n############## Wow expr is constant: ~w",[E]), Var = ?RTL:mk_new_var(), Value = eval_expr(E), Op = #const_expr{var = Var, value = Value}, {expr_is_const, Op}; false -> VisitedInstructions = lists:reverse(?BB:code(?CFG:bb(Cfg,P))), check_one_operand(E, VisitedInstructions, P, Cfg, XsiKey, XsiGraph) end; _ -> %% It's a merge point case expr_is_const(E) of true -> ?pp_debug("\n\n############## Wow expr is constant at merge point: ~w",[E]), Var = ?RTL:mk_new_var(), Value = eval_expr(E), Op = #const_expr{var = Var, value = Value}, {expr_is_const, Op}; false -> Temp = new_temp(), OpList = [#xsi_op{pred = X} || X <- Preds], Xsi = #xsi{inst = E, def = Temp, label = BlockLabel, opList = OpList}, {merge_point, Xsi} end end; check_one_operand(E, [CC|Rest], BlockLabel, Cfg, XsiKey, XsiGraph) -> SRC1 = ?RTL:alu_src1(E), SRC2 = ?RTL:alu_src2(E), %% C is the previous instruction case CC of #alu{} -> exit({?MODULE,should_not_be_an_alu, {"Why the hell do we still have an alu???",CC}}); #xsi{} -> exit({?MODULE,should_not_be_a_xsi, {"Why the hell do we still have a xsi???",CC}}); #pre_candidate{} -> C = CC#pre_candidate.alu, DST = ?RTL:alu_dst(C), case DST =:= SRC1 orelse DST =:= SRC2 of true -> %% Get the definition of C, since C is PRE-candidate AND has %% been processed before DEF = CC#pre_candidate.def, case DEF of bottom -> %% Def(E)=bottom, STOP %% No update of the XsiGraph {def_found,new_bottom()}; _-> %% Simply emend F = emend(E,DST,DEF), ?pp_debug("~nEmendation : E= ",[]),pp_expr(E),?pp_debug(" ==> E'= ",[]),pp_expr(F),?pp_debug("~n",[]), check_one_operand(F,Rest,BlockLabel,Cfg,XsiKey,XsiGraph) end; false -> case check_match(C,E) of true -> %% It's a computation of E! %% It should give DST and not Def %% No update of the XsiGraph, cuz we use DST and not Def %% The operand is therefore gonna be a real variable {def_found,DST}; _-> %% Nothing to do with E check_one_operand(E,Rest,BlockLabel,Cfg,XsiKey,XsiGraph) end end; #move{} -> %% It's a move, we emend E, and continue the definition search DST = ?RTL:move_dst(CC), case SRC1 =:= DST orelse SRC2 =:= DST of true -> SRC = ?RTL:move_src(CC), F = emend(E,DST,SRC), check_one_operand(F,Rest,BlockLabel,Cfg,XsiKey,XsiGraph); %% Continue the search _ -> check_one_operand(E,Rest,BlockLabel,Cfg,XsiKey,XsiGraph) %% Continue the search end; #xsi_link{} -> Key = CC#xsi_link.num, %% Is Key a family member of XsiDef ? {_KK,Xsi} = ?GRAPH:vertex(XsiGraph,Key), C = Xsi#xsi.inst, case check_match(E,C) of true -> %% There is a Xsi already with a computation of E! %% fetch definition of C, and give it to E %% Must update an edge in the XsiGraph, and here, we know it's a Temp %% Note: this can create a loop (= a cycle of length 1) ?pp_debug(" -- Found a cycle with match: Adding an edge t~w -> t~w",[XsiKey,Key]), ?GRAPH:add_edge(XsiGraph,XsiKey,Key), {def_found,Xsi#xsi.def}; _ -> case ?GRAPH:get_path(XsiGraph,Key,XsiKey) of false -> %% Is it a loop back to itself??? case Key =:= XsiKey of false -> check_one_operand(E,Rest,BlockLabel,Cfg,XsiKey,XsiGraph); _ -> {expr_found,#eop{expr=E,var=?RTL:mk_new_var(),stopped_by=Key}} end; _ -> %% Returning the expression instead of looping %% And in case of no match ExprOp = #eop{expr=E,var=?RTL:mk_new_var(),stopped_by=Key}, {expr_found,ExprOp} end end; #phi{} -> %% skip them check_one_operand(E,Rest,BlockLabel,Cfg,XsiKey,XsiGraph); _ -> PreColouredTest = ?ARCH:is_precoloured(SRC1) orelse ?ARCH:is_precoloured(SRC2), %%RegisterTest = ?RTL:is_reg(?RTL:alu_dst(E)) orelse ?RTL:is_reg(SRC1) orelse ?RTL:is_reg(SRC2), RegisterTest = ?RTL:is_reg(?RTL:alu_dst(E)), case PreColouredTest orelse RegisterTest of true -> {def_found,new_bottom()}; _-> DC = ?RTL:defines(CC), case lists:member(SRC1,DC) orelse lists:member(SRC2,DC) of true -> {def_found,new_bottom()}; _ -> %% Orthogonal to E, we continue the search check_one_operand(E,Rest,BlockLabel,Cfg,XsiKey,XsiGraph) end end end. eval_expr(E) -> ?pp_debug("~n Evaluating the result of ~w~n", [E]), Op1 = ?RTL:alu_src1(E), Op2 = ?RTL:alu_src2(E), true = ?RTL:is_imm(Op1), Val1 = ?RTL:imm_value(Op1), true = ?RTL:is_imm(Op2), Val2 = ?RTL:imm_value(Op2), {Result, _Sign, _Zero, _Overflow, _Carry} = ?ARCH:eval_alu(?RTL:alu_op(E), Val1, Val2), ?pp_debug("~n Result is then ~w~n", [Result]), ?RTL:mk_imm(Result). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%% CREATTING CFGGRAPH %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% create_cfggraph([],_Cfg,CFGGraph,ToBeFactorizedAcc,MPAcc,LateEdges,_XsiGraph) -> ?pp_debug("~n~n ############# PostProcessing ~n~w~n",[LateEdges]), post_process(LateEdges,CFGGraph), ?pp_debug("~n~n ############# Factorizing ~n~w~n",[ToBeFactorizedAcc]), factorize(ToBeFactorizedAcc,CFGGraph), MPAcc; create_cfggraph([Label|Ls],Cfg,CFGGraph,ToBeFactorizedAcc,MPAcc,LateEdges,XsiGraph) -> Preds = ?CFG:pred(Cfg, Label), case Preds of [] -> exit({?MODULE,do_not_call_on_top,{"Why the hell do we call that function on the start label???",Label}}); [P] -> Code = ?BB:code(?CFG:bb(Cfg, Label)), Defs = get_defs_in_non_merge_block(Code, []), ?pp_debug("~nAdding a vertex for ~w", [Label]), Succs = ?CFG:succ(Cfg, Label), NewToBeFactorizedAcc = case Succs of [] -> %% Exit point ?GRAPH:add_vertex(CFGGraph, Label, #block{type = exit}), ToBeFactorizedAcc; _ -> %% Split point ?GRAPH:add_vertex(CFGGraph,Label,#block{type=not_mp,attributes={P,Succs}}), [Label|ToBeFactorizedAcc] end, ?pp_debug("~nAdding an edge ~w -> ~w (~w)",[P,Label,Defs]), case ?GRAPH:add_edge(CFGGraph,P,Label,Defs) of {error,Reason} -> exit({?MODULE,forget_that_for_christs_sake_bingwen_please,{"Bad edge",Reason}}); _ -> ok end, create_cfggraph(Ls,Cfg,CFGGraph,NewToBeFactorizedAcc,MPAcc,LateEdges,XsiGraph); _ -> %% Merge point Code = ?BB:code(?CFG:bb(Cfg,Label)), {Defs,Xsis,Maps,Uses} = get_info_in_merge_block(Code,XsiGraph,[],[],gb_trees:empty(),gb_trees:empty()), Attributes = #mp{preds=Preds,xsis=Xsis,defs=Defs,maps=Maps,uses=Uses}, MergeBlock = #block{type=mp,attributes=Attributes}, ?pp_debug("~nAdding a vertex for ~w with Defs= ~w",[Label,Defs]), ?GRAPH:add_vertex(CFGGraph,Label,MergeBlock), %% Add edges NewLateEdges = add_edges_for_mp(Preds,Label,LateEdges), create_cfggraph(Ls,Cfg,CFGGraph,ToBeFactorizedAcc,[Label|MPAcc],NewLateEdges,XsiGraph) end. get_defs_in_non_merge_block([], Acc) -> ?SETS:from_list(Acc); get_defs_in_non_merge_block([Inst|Rest], Acc) -> case Inst of #pre_candidate{} -> Def = Inst#pre_candidate.def, case Def of #temp{} -> %% {temp,Key,_Var} -> %% get_defs_in_non_merge_block(Rest,[Key|Acc]); get_defs_in_non_merge_block(Rest, [Def#temp.key|Acc]); _-> %% Real variables or bottom get_defs_in_non_merge_block(Rest, Acc) end; _ -> get_defs_in_non_merge_block(Rest, Acc) end. get_info_in_merge_block([],_XsiGraph,Defs,Xsis,Maps,Uses) -> {?SETS:from_list(Defs),Xsis,Maps,Uses}; %% Xsis are in backward order get_info_in_merge_block([Inst|Rest],XsiGraph,Defs,Xsis,Maps,Uses) -> case Inst of #pre_candidate{} -> Def = Inst#pre_candidate.def, case Def of #temp{} -> get_info_in_merge_block(Rest,XsiGraph,[Def#temp.key|Defs],Xsis,Maps,Uses); _ -> get_info_in_merge_block(Rest,XsiGraph,Defs,Xsis,Maps,Uses) end; #xsi_link{} -> Key = Inst#xsi_link.num, {_Key,Xsi} = ?GRAPH:vertex(XsiGraph,Key), OpList = xsi_oplist(Xsi), {NewMaps,NewUses} = add_map_and_uses(OpList,Key,Maps,Uses), get_info_in_merge_block(Rest,XsiGraph,Defs,[Key|Xsis],NewMaps,NewUses); _ -> get_info_in_merge_block(Rest,XsiGraph,Defs,Xsis,Maps,Uses) end. add_edges_for_mp([], _Label, LateEdges) -> LateEdges; add_edges_for_mp([P|Ps], Label, LateEdges) -> add_edges_for_mp(Ps,Label,[{P,Label}|LateEdges]). %% Doesn't do anything so far add_map_and_uses([], _Key, Maps, Uses) -> {Maps, Uses}; add_map_and_uses([XsiOp|Ops], Key, Maps, Uses) -> {NewMaps, NewUses} = case XsiOp#xsi_op.op of #bottom{} -> Set = case gb_trees:lookup(XsiOp, Maps) of {value, V} -> ?SETS:add_element(Key, V); none -> ?SETS:from_list([Key]) end, {gb_trees:enter(XsiOp, Set, Maps), Uses}; #temp{} -> Set = case gb_trees:lookup(XsiOp, Maps) of {value, V} -> ?SETS:add_element(Key, V); none -> ?SETS:from_list([Key]) end, Pred = XsiOp#xsi_op.pred, OOP = XsiOp#xsi_op.op, SSet = case gb_trees:lookup(Pred, Uses) of {value, VV} -> ?SETS:add_element(OOP#temp.key, VV); none -> ?SETS:from_list([OOP#temp.key]) end, {gb_trees:enter(XsiOp, Set, Maps), gb_trees:enter(Pred, SSet, Uses)}; #eop{} -> Set = case gb_trees:lookup(XsiOp, Maps) of {value, V} -> ?SETS:add_element(Key, V); none -> ?SETS:from_list([Key]) end, Pred = XsiOp#xsi_op.pred, Op = XsiOp#xsi_op.op, SSet = case gb_trees:lookup(Pred, Uses) of {value, VV} -> ?SETS:add_element(Op#eop.stopped_by, VV); none -> ?SETS:from_list([Op#eop.stopped_by]) end, {gb_trees:enter(XsiOp, Set, Maps), gb_trees:enter(Pred, SSet, Uses)}; _-> {Maps, Uses} end, add_map_and_uses(Ops, Key, NewMaps, NewUses). post_process([], _CFGGraph) -> ok; post_process([E|Es], CFGGraph) -> {Pred,Label} = E, {_PP,Block} = ?GRAPH:vertex(CFGGraph,Label), Att = Block#block.attributes, Uses = Att#mp.uses, SetToAdd = case gb_trees:lookup(Pred,Uses) of {value, Set} -> Set; none -> ?SETS:new() end, %% ?pp_debug("~nAdding an edge ~w -> ~w (~w)",[Pred,Label,SetToAdd]), ?GRAPH:add_edge(CFGGraph, Pred, Label, SetToAdd), post_process(Es, CFGGraph). factorize([], _CFGGraph) -> ok; factorize([P|Ps], CFGGraph) -> [OE|OEs] = ?GRAPH:out_edges(CFGGraph,P), %% ?pp_debug("~nIn_degrees ~w : ~w",[P,?GRAPH:in_degree(CFGGraph,P)]), [InEdge] = ?GRAPH:in_edges(CFGGraph,P), {E,V1,V2,Label} = ?GRAPH:edge(CFGGraph,InEdge), {_OEE,_OEV1,_OEV2,LOE} = ?GRAPH:edge(CFGGraph,OE), List = shoot_info_upwards(OEs,LOE,CFGGraph), NewLabel = ?SETS:union(Label,List), ?GRAPH:add_edge(CFGGraph,E,V1,V2,NewLabel), factorize(Ps, CFGGraph). shoot_info_upwards([], Acc, _CFGGraph) -> Acc; shoot_info_upwards([E|Es], Acc, CFGGraph) -> {_E,_V1,_V2,Set} = ?GRAPH:edge(CFGGraph,E), NewAcc = ?SETS:intersection(Acc, Set), case ?SETS:size(NewAcc) of 0 -> NewAcc; _ -> shoot_info_upwards(Es,NewAcc,CFGGraph) end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% DOWNSAFETY %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% perform_downsafety([], _G, _XsiG) -> ok; perform_downsafety([MP|MPs], G, XG) -> {V,Block} = ?GRAPH:vertex(G, MP), NDS = ?SETS:new(), Att = Block#block.attributes, Maps = Att#mp.maps, Defs = Att#mp.defs, OutEdges = ?GRAPH:out_edges(G, MP), %% ?pp_debug("~n Inspection Maps : ~w",[Maps]), NewNDS = parse_keys(gb_trees:keys(Maps),Maps,OutEdges,G,Defs,NDS,XG), NewAtt = Att#mp{ndsSet = NewNDS}, ?GRAPH:add_vertex(G, V, Block#block{attributes = NewAtt}), ?pp_debug("~n Not Downsafe at L~w: ~w", [V, NewNDS]), %%io:format(standard_io,"~n Not Downsafe at L~w: ~w",[V,NewNDS]), perform_downsafety(MPs, G, XG). parse_keys([], _Maps, _OutEdges, _G, _Defs, NDS, _XsiG) -> NDS; parse_keys([M|Ms], Maps, OutEdges, G, Defs, NDS, XsiG) -> KillerSet = gb_trees:get(M,Maps), %% ?pp_debug("~n Inspection ~w -> ~w",[M,KillerSet]), TempSet = ?SETS:intersection(KillerSet,Defs), NewNDS = case ?SETS:size(TempSet) of 0 -> getNDS(M,KillerSet,NDS,OutEdges,G,XsiG); _ -> %% One Xsi which has M as operand has killed it %% M is then Downsafe %% and is not added to the NotDownsafeSet (NDS) NDS end, parse_keys(Ms, Maps, OutEdges, G, Defs, NewNDS, XsiG). getNDS(_M, _KillerSet, NDS, [], _G, _XsiG) -> NDS; getNDS(M, KillerSet, NDS, [E|Es], G, XsiG) -> {_EE,_V1,_V2,Label} = ?GRAPH:edge(G, E), Set = ?SETS:intersection(KillerSet, Label), %% ?pp_debug("~n ######## Intersection between KillerSet: ~w and Label: ~w",[KillerSet,Label]), %% ?pp_debug("~n ######## ~w",[Set]), case ?SETS:size(Set) of 0 -> %% M is not downsafe ?SETS:add_element(M, NDS); _ -> %% Try the other edges getNDS(M, KillerSet, NDS, Es, G, XsiG) end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%% WILL BE AVAILABLE %%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% perform_will_be_available(XsiGraph,CFGGraph,Options) -> Keys = ?GRAPH:vertices(XsiGraph), ?pp_debug("~n############ Can Be Available ##########~n",[]), ?option_time(perform_can_be_available(Keys,XsiGraph,CFGGraph),"RTL A-SSAPRE WillBeAvailable - Compute CanBeAvailable",Options), ?pp_debug("~n############ Later ##########~n",[]), ?option_time(perform_later(Keys,XsiGraph),"RTL A-SSAPRE WillBeAvailable - Compute Later",Options). perform_can_be_available([],_XsiGraph,_CFGGraph) -> ok; perform_can_be_available([Key|Keys],XsiGraph,CFGGraph) -> {V,Xsi} = ?GRAPH:vertex(XsiGraph,Key), case Xsi#xsi.cba of undefined -> {_VV,Block} = ?GRAPH:vertex(CFGGraph,Xsi#xsi.label), Att = Block#block.attributes, NDS = Att#mp.ndsSet, OpList = ?SETS:from_list(xsi_oplist(Xsi)), Set = ?SETS:intersection(NDS,OpList), case ?SETS:size(Set) of 0 -> ?GRAPH:add_vertex(XsiGraph, V, Xsi#xsi{cba = true}), perform_can_be_available(Keys, XsiGraph, CFGGraph); _ -> LIST = [X || #temp{key=X} <- ?SETS:to_list(Set)], case LIST of [] -> ?GRAPH:add_vertex(XsiGraph, V, Xsi#xsi{cba = false}), ImmediateParents = ?GRAPH:in_neighbours(XsiGraph, Key), propagate_cba(ImmediateParents,XsiGraph,Xsi#xsi.def,CFGGraph); _ -> ok end, perform_can_be_available(Keys, XsiGraph, CFGGraph) end; _ -> %% True or False => recurse perform_can_be_available(Keys, XsiGraph, CFGGraph) end. propagate_cba([],_XG,_Def,_CFGG) -> ok; propagate_cba([IPX|IPXs],XsiGraph,XsiDef,CFGGraph) -> {V,IPXsi} = ?GRAPH:vertex(XsiGraph,IPX), {_VV,Block} = ?GRAPH:vertex(CFGGraph,IPXsi#xsi.label), Att = Block#block.attributes, NDS = Att#mp.ndsSet, List = ?SETS:to_list(?SETS:intersection(NDS,?SETS:from_list(xsi_oplist(IPXsi)))), case IPXsi#xsi.cba of false -> ok; _ -> case lists:keymember(XsiDef, #xsi_op.op, List) of true -> ?GRAPH:add_vertex(XsiGraph, V, IPXsi#xsi{cba = false}), ImmediateParents = ?GRAPH:in_neighbours(XsiGraph, IPX), propagate_cba(ImmediateParents,XsiGraph,IPXsi#xsi.def,CFGGraph); _ -> ok end end, propagate_cba(IPXs,XsiGraph,XsiDef,CFGGraph). perform_later([], _XsiGraph) -> ok; perform_later([Key|Keys], XsiGraph) -> {V, Xsi} = ?GRAPH:vertex(XsiGraph, Key), %% ?pp_debug("~n DEBUG : inspecting later of ~w (~w)~n",[Key,Xsi#xsi.later]), case Xsi#xsi.later of undefined -> OpList = xsi_oplist(Xsi), case parse_ops(OpList,fangpi) of %% It means "fart" in chinese :D has_temp -> perform_later(Keys,XsiGraph); has_real -> case Xsi#xsi.cba of true -> ?GRAPH:add_vertex(XsiGraph,V,Xsi#xsi{later=false,wba=true}); undefined -> ?GRAPH:add_vertex(XsiGraph,V,Xsi#xsi{later=false,wba=true}); _ -> ?GRAPH:add_vertex(XsiGraph,V,Xsi#xsi{later=false,wba=false}) end, AllParents = digraph_utils:reaching([Key], XsiGraph), ?pp_debug("~nPropagating to all parents of t~w: ~w",[Key,AllParents]), propagate_later(AllParents,XsiGraph), perform_later(Keys,XsiGraph); _ -> %% Just contains bottoms and/or expressions ?GRAPH:add_vertex(XsiGraph,V,Xsi#xsi{later=true}), perform_later(Keys,XsiGraph) end; _ -> %% True or False => recurse perform_later(Keys,XsiGraph) end. propagate_later([], _XG) -> ok; propagate_later([IPX|IPXs], XsiGraph) -> {V,IPXsi} = ?GRAPH:vertex(XsiGraph,IPX), case IPXsi#xsi.later of false -> ?pp_debug("~nThrough propagation, later of t~w is already reset",[IPX]), propagate_later(IPXs,XsiGraph); _ -> ?pp_debug("~nThrough propagation, resetting later of t~w",[IPX]), case IPXsi#xsi.cba of true -> ?GRAPH:add_vertex(XsiGraph,V,IPXsi#xsi{later=false,wba=true}); undefined -> ?GRAPH:add_vertex(XsiGraph,V,IPXsi#xsi{later=false,wba=true}); _ -> ?GRAPH:add_vertex(XsiGraph,V,IPXsi#xsi{later=false,wba=false}) end, propagate_later(IPXs,XsiGraph) end. parse_ops([], Res) -> Res; parse_ops([Op|Ops], Res) -> case Op#xsi_op.op of #temp{} -> NewRes = has_temp, parse_ops(Ops,NewRes); #bottom{} -> parse_ops(Ops,Res); #eop{} -> parse_ops(Ops,Res); _ -> has_real end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% CODE MOTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% perform_code_motion([], Cfg, _XsiG) -> Cfg; perform_code_motion([L|Labels], Cfg, XsiG) -> Code=?BB:code(?CFG:bb(Cfg,L)), ?pp_debug("~n################ Code Motion in L~w~n",[L]), ?pp_debug("~nCode to move ~n",[]), pp_instrs(Code,XsiG), NewCfg = code_motion_in_block(L,Code,Cfg,XsiG,[],gb_trees:empty()), ?pp_debug("~n################ Code Motion successful in L~w~n",[L]), perform_code_motion(Labels,NewCfg,XsiG). code_motion_in_block(Label,[],Cfg,_XsiG,Visited,InsertionsAcc) -> InsertionsAlong = gb_trees:keys(InsertionsAcc), Code = lists:reverse(Visited), NewBB = ?BB:mk_bb(Code), Cfg2 = ?CFG:bb_add(Cfg,Label,NewBB), %% Must come after the bb_add, since redirect will update the Phis too... Cfg3 = make_insertions(Label,InsertionsAlong,InsertionsAcc,Cfg2), %% ?pp_debug("~nChecking the Code at L~w:~n~p",[Label,?BB:code(?CFG:bb(Cfg3,Label))]), Cfg3; code_motion_in_block(L,[Inst|Insts],Cfg,XsiG,Visited,InsertionsAcc) -> ?pp_debug("~nInspecting Inst : ~n",[]),pp_instr(Inst,XsiG), case Inst of #pre_candidate{} -> Def = Inst#pre_candidate.def, Alu = Inst#pre_candidate.alu, InstToAdd = case Def of bottom -> Alu; #temp{} -> Key = Def#temp.key, {_V,Xsi} = ?GRAPH:vertex(XsiG,Key), case Xsi#xsi.wba of true -> %% Turn into a move Dst = ?RTL:alu_dst(Alu), Move = ?RTL:mk_move(Dst,Def#temp.var), pp_instr(Inst#pre_candidate.alu,nil), ?pp_debug(" ==> ",[]), pp_instr(Move,nil), %% Counting redundancies redundancy_add(), Move; _ -> Alu end; _ -> %% Def is a real variable %% Turn into a move Dst = ?RTL:alu_dst(Alu), Move = ?RTL:mk_move(Dst,Def), pp_instr(Alu,nil), ?pp_debug(" ==> ",[]), pp_instr(Move,nil), %% Counting redundancies redundancy_add(), Move end, code_motion_in_block(L,Insts,Cfg,XsiG,[InstToAdd|Visited],InsertionsAcc); #xsi_link{} -> Key = Inst#xsi_link.num, {_V,Xsi} = ?GRAPH:vertex(XsiG,Key), case Xsi#xsi.wba of true -> %% Xsi is a WBA, it might trigger insertions OpList = xsi_oplist(Xsi), ?pp_debug(" This Xsi is a 'Will be available'",[]), %% Cleaning the instruction Expr = prepare_inst(Xsi#xsi.inst), {NewOpList,NewInsertionsAcc} = get_insertions(OpList,[],InsertionsAcc,Visited,Expr,XsiG), %% Making Xsi a Phi with Oplist PhiOpList = [{Pred,Var} || #xsi_op{pred=Pred,op=Var} <- NewOpList], Def = Xsi#xsi.def, Phi = ?RTL:phi_arglist_update(?RTL:mk_phi(Def#temp.var),PhiOpList), ?pp_debug("~n Xsi is turned into Phi : ~w",[Phi]), code_motion_in_block(L,Insts,Cfg,XsiG,[Phi|Visited],NewInsertionsAcc); _ -> ?pp_debug(" This Xsi is not a 'Will be available'",[]), code_motion_in_block(L,Insts,Cfg,XsiG,Visited,InsertionsAcc) end; %% phi -> %% code_motion_in_block(L,Insts,Cfg,XsiG,[Inst|Visited],InsertionsAcc); _ -> %% Other instructions.... Phis too code_motion_in_block(L,Insts,Cfg,XsiG,[Inst|Visited],InsertionsAcc) end. prepare_inst(Expr) -> S1 = ?RTL:alu_src1(Expr), S2 = ?RTL:alu_src2(Expr), NewInst = case S1 of #temp{} -> ?RTL:alu_src1_update(Expr,S1#temp.var); _ -> Expr end, case S2 of #temp{} -> ?RTL:alu_src2_update(NewInst,S2#temp.var); _ -> NewInst end. get_insertions([],OpAcc,InsertionsAcc,_Visited,_Expr,_XsiG) -> {OpAcc,InsertionsAcc}; get_insertions([XsiOp|Ops],OpAcc,InsertionsAcc,Visited,Expr,XsiG) -> Pred = XsiOp#xsi_op.pred, Op = XsiOp#xsi_op.op, {Dst, NewInsertionsAcc} = case Op of #bottom{} -> case gb_trees:lookup(Pred,InsertionsAcc) of {value,Insertion} -> From = Insertion#insertion.from, case lists:keyfind(Op, 1, From) of false -> ?pp_debug("~nThere has been insertions along the edge L~w already, but not for that operand | Op=",[Pred]),pp_arg(Op), D = Op#bottom.var, Expr2 = ?RTL:alu_dst_update(Expr,D), Inst = manufacture_computation(Pred,Expr2,Visited), Code = Insertion#insertion.code, NewInsertion = Insertion#insertion{from=[{Op,D}|From],code=[Inst|Code]}, {D, gb_trees:update(Pred, NewInsertion, InsertionsAcc)}; {_, Val} -> ?pp_debug("~nThere has been insertions along the edge L~w already, and for that operand too | Op=",[Pred]),pp_arg(Op), {Val, InsertionsAcc} end; none -> ?pp_debug("~nThere has been no insertion along the edge L~w, (and not for that operand, of course)| Op=",[Pred]),pp_arg(Op), D = Op#bottom.var, Expr2 = ?RTL:alu_dst_update(Expr, D), Inst = manufacture_computation(Pred,Expr2,Visited), NewInsertion = #insertion{from=[{Op,D}],code=[Inst]}, {D, gb_trees:insert(Pred,NewInsertion, InsertionsAcc)} end; #const_expr{} -> case gb_trees:lookup(Pred,InsertionsAcc) of {value,Insertion} -> From = Insertion#insertion.from, case lists:keyfind(Op, 1, From) of false -> ?pp_debug("~nThere have been insertions along the edge L~w already, but not for that operand | Op=",[Pred]),pp_arg(Op), D = Op#const_expr.var, Val = Op#const_expr.value, Inst = ?RTL:mk_move(D, Val), Code = Insertion#insertion.code, NewInsertion = Insertion#insertion{from=[{Op,D}|From],code=[Inst|Code]}, {D, gb_trees:update(Pred,NewInsertion,InsertionsAcc)}; {_, Val} -> ?pp_debug("~nThere have been insertions along the edge L~w already, and for that operand too | Op=",[Pred]),pp_arg(Op), {Val, InsertionsAcc} end; none -> ?pp_debug("~nThere has been no insertion along the edge L~w, (and not for that operand, of course)| Op=",[Pred]),pp_arg(Op), D = Op#const_expr.var, Val = Op#const_expr.value, Inst = ?RTL:mk_move(D, Val), NewInsertion = #insertion{from=[{Op,D}],code=[Inst]}, {D, gb_trees:insert(Pred,NewInsertion, InsertionsAcc)} end; #eop{} -> %% We treat expressions like bottoms %% The value must be recomputed, and therefore not available... case gb_trees:lookup(Pred,InsertionsAcc) of {value,Insertion} -> From = Insertion#insertion.from, case lists:keyfind(Op, 1, From) of false -> ?pp_debug("~nThere has been insertions along the edge L~w already, but not for that operand | Op=",[Pred]),pp_arg(Op), D = Op#eop.var, Expr2 = ?RTL:alu_dst_update(Expr, D), Inst = manufacture_computation(Pred,Expr2,Visited), Code = Insertion#insertion.code, NewInsertion = Insertion#insertion{from=[{Op,D}|From],code=[Inst|Code]}, {D, gb_trees:update(Pred,NewInsertion, InsertionsAcc)}; {_, Val} -> ?pp_debug("~nThere has been insertions along the edge L~w already, and for that operand too | Op=",[Pred]),pp_arg(Op), {Val, InsertionsAcc} end; none -> ?pp_debug("~nThere has been no insertion along the edge L~w, (and not for that operand, of course)| Op=",[Pred]),pp_arg(Op), D = Op#eop.var, Expr2 = ?RTL:alu_dst_update(Expr, D), Inst = manufacture_computation(Pred,Expr2,Visited), NewInsertion = #insertion{from=[{Op,D}],code=[Inst]}, {D, gb_trees:insert(Pred, NewInsertion, InsertionsAcc)} end; #temp{} -> case gb_trees:lookup(Pred,InsertionsAcc) of {value,Insertion} -> From = Insertion#insertion.from, case lists:keyfind(Op, 1, From) of false -> ?pp_debug("~nThere has been insertions along the edge L~w already, but not for that operand | Op=",[Pred]),pp_arg(Op), Key = Op#temp.key, {_V,Xsi} = ?GRAPH:vertex(XsiG,Key), case Xsi#xsi.wba of true -> ?pp_debug("~nBut the operand is a WBA Xsi: no need for insertion",[]), {Op#temp.var, InsertionsAcc}; _ -> ?pp_debug("~nBut the operand is a NOT WBA Xsi: we must make an insertion",[]), D = ?RTL:mk_new_var(), Expr2 = ?RTL:alu_dst_update(Expr, D), Inst = manufacture_computation(Pred,Expr2,Visited), Code = Insertion#insertion.code, NewInsertion = Insertion#insertion{from=[{Op,D}|From],code=[Inst|Code]}, {D, gb_trees:update(Pred, NewInsertion, InsertionsAcc)} end; {_, Val} -> ?pp_debug("~nThere has been insertions along the edge L~w already, and for that operand too (Op=~w)",[Pred,Op]), ?pp_debug("~nThis means, this temp is a WBA Xsi's definition",[]), {Val, InsertionsAcc} end; none -> ?pp_debug("~nThere has been no insertion along the edge L~w, (and not for that operand, of course | Op=",[Pred]),pp_arg(Op), Key = Op#temp.key, {_V,Xsi} = ?GRAPH:vertex(XsiG,Key), case Xsi#xsi.wba of true -> ?pp_debug("~nBut the operand is a WBA Xsi: no need for insertion",[]), {Op#temp.var, InsertionsAcc}; _ -> ?pp_debug("~nBut the operand is a NOT WBA Xsi: we must make an insertion",[]), D = ?RTL:mk_new_var(), Expr2 = ?RTL:alu_dst_update(Expr, D), Inst = manufacture_computation(Pred,Expr2,Visited), NewInsertion = #insertion{from=[{Op,D}],code=[Inst]}, {D, gb_trees:insert(Pred, NewInsertion, InsertionsAcc)} end end; _ -> ?pp_debug("~nThe operand (Op=",[]),pp_arg(Op),?pp_debug(") is a real variable, no need for insertion along L~w",[Pred]), {Op, InsertionsAcc} end, NewXsiOp = XsiOp#xsi_op{op=Dst}, get_insertions(Ops, [NewXsiOp|OpAcc], NewInsertionsAcc, Visited, Expr, XsiG). manufacture_computation(_Pred, Expr, []) -> ?pp_debug("~n Manufactured computation : ~w", [Expr]), Expr; manufacture_computation(Pred, Expr, [I|Rest]) -> %% ?pp_debug("~n Expr = ~w",[Expr]), SRC1 = ?RTL:alu_src1(Expr), SRC2 = ?RTL:alu_src2(Expr), case I of #xsi_link{} -> exit({?MODULE,should_not_be_a_xsi_link,{"Why the hell do we still have a xsi link???",I}}); #xsi{} -> exit({?MODULE,should_not_be_a_xsi,{"Why the hell do we still have a xsi ???",I}}); #phi{} -> DST = ?RTL:phi_dst(I), Arg = ?RTL:phi_arg(I,Pred), NewInst = case DST =:= SRC1 of true -> ?RTL:alu_src1_update(Expr,Arg); false -> Expr end, NewExpr = case DST =:= SRC2 of true -> ?RTL:alu_src2_update(NewInst,Arg); false -> NewInst end, manufacture_computation(Pred,NewExpr,Rest) end. make_insertions(_L, [], _ITree, Cfg) -> Cfg; make_insertions(L, [OldPred|Is], ITree, Cfg) -> NewPred = ?RTL:label_name(?RTL:mk_new_label()), I = gb_trees:get(OldPred, ITree), CodeToInsert = lists:reverse([?RTL:mk_goto(L)|I#insertion.code]), BBToInsert = ?BB:mk_bb(CodeToInsert), NewCfg = ?CFG:bb_insert_between(Cfg, NewPred, BBToInsert, OldPred, L), make_insertions(L, Is, ITree, NewCfg). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%% XSI INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% xsi_oplist(#xsi{opList=OpList}) -> case OpList of undefined -> [] ; _ -> OpList end. xsi_arg(Xsi, Pred) -> case lists:keyfind(Pred, #xsi_op.pred, xsi_oplist(Xsi)) of false -> undetermined_operand; R -> R#xsi_op.op end. xsi_arg_update(Xsi, Pred, Op) -> NewOpList = lists:keyreplace(Pred, #xsi_op.pred, xsi_oplist(Xsi), #xsi_op{pred=Pred,op=Op}), Xsi#xsi{opList=NewOpList}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%% PRETTY-PRINTING %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -ifndef(SSAPRE_DEBUG). %%pp_cfg(Cfg,_) -> ?CFG:pp(Cfg). pp_cfg(_,_) -> ok. pp_instr(_,_) -> ok. pp_instrs(_,_) -> ok. pp_expr(_) -> ok. pp_xsi(_) -> ok. pp_arg(_) -> ok. pp_xsigraph(_) -> ok. pp_cfggraph(_) -> ok. %% pp_xsigraph(G) -> %% Vertices = lists:sort(?GRAPH:vertices(G)), %% io:format(standard_io, "Size of the Xsi Graph: ~w", [length(Vertices)]). %% pp_cfggraph(G) -> %% Vertices = lists:sort(?GRAPH:vertices(G)), %% io:format(standard_io, "Size of the CFG Graph: ~w", [length(Vertices)]). -else. pp_cfg(Cfg, Graph) -> Labels = ?CFG:preorder(Cfg), pp_blocks(Labels, Cfg, Graph). pp_blocks([], _, _) -> ok; pp_blocks([L|Ls], Cfg, Graph) -> Code = hipe_bb:code(?CFG:bb(Cfg,L)), io:format(standard_io,"~n########## Label L~w~n", [L]), pp_instrs(Code, Graph), pp_blocks(Ls, Cfg, Graph). pp_instrs([], _) -> ok; pp_instrs([I|Is], Graph) -> pp_instr(I, Graph), pp_instrs(Is, Graph). pp_xsi_link(Key, Graph) -> {_Key,Xsi} = ?GRAPH:vertex(Graph, Key), pp_xsi(Xsi). pp_xsi(Xsi) -> io:format(standard_io, " [L~w] ", [Xsi#xsi.label]), io:format(standard_io, "[", []), pp_expr(Xsi#xsi.inst), io:format(standard_io, "] Xsi(", []), pp_xsi_args(xsi_oplist(Xsi)), io:format(standard_io, ") (", []), pp_xsi_def(Xsi#xsi.def), io:format(standard_io, ") cba=~w, later=~w | wba=~w~n", [Xsi#xsi.cba,Xsi#xsi.later,Xsi#xsi.wba]). pp_instr(I, Graph) -> case I of #alu{} -> io:format(standard_io, " ", []), pp_arg(?RTL:alu_dst(I)), io:format(standard_io, " <- ", []), pp_expr(I), io:format(standard_io, "~n", []); _ -> try ?RTL:pp_instr(standard_io, I) catch _:_ -> case I of #pre_candidate{} -> pp_pre(I); #xsi{} -> pp_xsi(I); #xsi_link{} -> pp_xsi_link(I#xsi_link.num, Graph); _-> io:format(standard_io,"*** ~w ***~n", [I]) end end end. pp_pre(I) -> A = I#pre_candidate.alu, io:format(standard_io, " ", []), pp_arg(?RTL:alu_dst(A)), io:format(standard_io, " <- ", []),pp_expr(A), io:format(standard_io, " [ ", []),pp_arg(I#pre_candidate.def), %%io:format(standard_io, "~w", [I#pre_candidate.def]), io:format(standard_io, " ]~n",[]). pp_expr(I) -> pp_arg(?RTL:alu_dst(I)), io:format(standard_io, " <- ", []), pp_arg(?RTL:alu_src1(I)), io:format(standard_io, " ~w ", [?RTL:alu_op(I)]), pp_arg(?RTL:alu_src2(I)). pp_arg(Arg) -> case Arg of bottom -> io:format(standard_io, "_|_", []); #bottom{} -> io:format(standard_io, "_|_:~w (", [Arg#bottom.key]),pp_arg(Arg#bottom.var),io:format(standard_io,")",[]); #temp{} -> pp_xsi_def(Arg); #eop{} -> io:format(standard_io,"#",[]),pp_expr(Arg#eop.expr),io:format(standard_io,"(",[]),pp_arg(Arg#eop.var),io:format(standard_io,")#",[]); #const_expr{} -> io:format(standard_io,"*",[]),pp_arg(Arg#const_expr.var),io:format(standard_io," -> ",[]),pp_arg(Arg#const_expr.value),io:format(standard_io,"*",[]); undefined -> io:format(standard_io, "...", []); %%"undefined", []); _-> case Arg of #alu{} -> pp_expr(Arg); _-> ?RTL:pp_arg(standard_io, Arg) end end. pp_args([]) -> ok; pp_args(undefined) -> io:format(standard_io, "...,...,...", []); pp_args([A]) -> pp_arg(A); pp_args([A|As]) -> pp_arg(A), io:format(standard_io, ", ", []), pp_args(As). pp_xsi_args([]) -> ok; pp_xsi_args([XsiOp]) -> io:format(standard_io, "{~w| ", [XsiOp#xsi_op.pred]), pp_arg(XsiOp#xsi_op.op), io:format(standard_io, "}", []); pp_xsi_args([XsiOp|Args]) -> io:format(standard_io, "{~w| ", [XsiOp#xsi_op.pred]), pp_arg(XsiOp#xsi_op.op), io:format(standard_io, "}, ", []), pp_xsi_args(Args); pp_xsi_args(Args) -> pp_args(Args). pp_xsi_def(Arg) -> D = Arg#temp.key, V = Arg#temp.var, io:format(standard_io, "t~w (", [D]),pp_arg(V),io:format(standard_io,")",[]). pp_cfggraph(G) -> Vertices = lists:sort(?GRAPH:vertices(G)), io:format(standard_io, "Size of the CFG Graph: ~w ~n", [length(Vertices)]), pp_cfgvertex(Vertices, G). pp_xsigraph(G) -> Vertices = lists:sort(?GRAPH:vertices(G)), io:format(standard_io, "Size of the Xsi Graph: ~w ~n", [length(Vertices)]), pp_xsivertex(Vertices,G). pp_xsivertex([], _G) -> ok; pp_xsivertex([Key|Keys], G) -> {V,Xsi} = ?GRAPH:vertex(G, Key), OutNeighbours = ?GRAPH:out_neighbours(G, V), ?pp_debug(" ~w -> ~w", [V,OutNeighbours]), pp_xsi(Xsi), pp_xsivertex(Keys, G). pp_cfgvertex([], _G) -> ok; pp_cfgvertex([Key|Keys], G) -> {V,Block} = ?GRAPH:vertex(G,Key), case Block#block.type of mp -> ?pp_debug("~n Block ~w's attributes: ~n", [V]), pp_attributes(Block), ?pp_debug("~n Block ~w's edges: ~n", [V]), pp_edges(G, ?GRAPH:in_edges(G,Key), ?GRAPH:out_edges(G,Key)); _-> ok end, pp_cfgvertex(Keys, G). pp_attributes(Block) -> Att = Block#block.attributes, case Att of undefined -> ok; _ -> ?pp_debug(" Maps: ~n",[]),pp_maps(gb_trees:keys(Att#mp.maps),Att#mp.maps), ?pp_debug(" Uses: ~n",[]),pp_uses(gb_trees:keys(Att#mp.uses),Att#mp.uses), ?pp_debug(" Defs: ~w~n",[Att#mp.defs]), ?pp_debug(" Xsis: ~w~n",[Att#mp.xsis]), ?pp_debug(" NDS : ",[]),pp_nds(?SETS:to_list(Att#mp.ndsSet)) end. pp_maps([], _Maps) -> ok; pp_maps([K|Ks], Maps) -> ?pp_debug(" ",[]),pp_arg(K#xsi_op.op),?pp_debug("-> ~w~n",[?SETS:to_list(gb_trees:get(K,Maps))]), pp_maps(Ks, Maps). pp_uses([], _Maps) -> ok; pp_uses([K|Ks], Maps) -> ?pp_debug(" ~w -> ~w~n",[K,?SETS:to_list(gb_trees:get(K,Maps))]), pp_uses(Ks, Maps). pp_nds([]) -> ?pp_debug("~n",[]); pp_nds(undefined) -> ?pp_debug("None",[]); pp_nds([K]) -> pp_arg(K#xsi_op.op), ?pp_debug("~n",[]); pp_nds([K|Ks]) -> pp_arg(K#xsi_op.op), ?pp_debug(", ",[]), pp_nds(Ks). pp_edges(_G, [], []) -> ok; pp_edges(G, [], [OUT|OUTs]) -> {_E,V1,V2,Label} = ?GRAPH:edge(G,OUT), ?pp_debug(" Out edge ~w -> ~w (~w)~n", [V1,V2,?SETS:to_list(Label)]), pp_edges(G, [], OUTs); pp_edges(G, [IN|INs], Outs) -> {_E,V1,V2,Label} = ?GRAPH:edge(G,IN), ?pp_debug(" In edge ~w -> ~w (~w)~n", [V1,V2,?SETS:to_list(Label)]), pp_edges(G, INs, Outs). -endif. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% COUNTERS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% init_counters() -> put({ssapre_temp,temp_count}, 0), put({ssapre_index,index_count}, 0). new_bottom() -> IndxCountPair = {ssapre_index, index_count}, V = get(IndxCountPair), put(IndxCountPair, V+1), #bottom{key = V, var = ?RTL:mk_new_var()}. new_temp() -> TmpCountPair = {ssapre_temp, temp_count}, V = get(TmpCountPair), put(TmpCountPair, V+1), #temp{key = V, var = ?RTL:mk_new_var()}. init_redundancy_count() -> put({ssapre_redundancy,redundancy_count}, 0). redundancy_add() -> RedCountPair = {ssapre_redundancy, redundancy_count}, V = get(RedCountPair), put(RedCountPair, V+1). -ifdef(SSAPRE_DEBUG). get_redundancy_count() -> get({ssapre_redundancy,redundancy_count}). -endif.