aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe/rtl/hipe_rtl_ssapre.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hipe/rtl/hipe_rtl_ssapre.erl')
-rw-r--r--lib/hipe/rtl/hipe_rtl_ssapre.erl1679
1 files changed, 1679 insertions, 0 deletions
diff --git a/lib/hipe/rtl/hipe_rtl_ssapre.erl b/lib/hipe/rtl/hipe_rtl_ssapre.erl
new file mode 100644
index 0000000000..a9e92e5688
--- /dev/null
+++ b/lib/hipe/rtl/hipe_rtl_ssapre.erl
@@ -0,0 +1,1679 @@
+%% -*- erlang-indent-level: 2 -*-
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% 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 <a href="http://cs.wheaton.edu/%7Etvandrun/writings/spessapre.pdf">Anticipation-SSAPRE algorithm</a>,
+%% 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
+ ?option_time(?pp_debug("~n~n################ No Xsi Inserted ################~n",[]),"RTL A-SSAPRE No Xsi inserted (skip Downsafety and Will Be Available)",Options),
+ 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(),
+ ?option_time(FinalCFG=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 carefull, 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",[]),
+ ?option_time({Cfg2,XsiGraph} = 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",[]),
+ ?option_time({Cfg3,XsiGraph} = 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
+ ?option_time(MPs=create_cfggraph(Others,Cfg3,CFGGraph,[],[],[],XsiGraph),"RTL A-SSAPRE Xsi Insertion, creating intermediate 'SSAPRE Graph'",Options),
+
+ %% Return the bloody 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,
+ 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),
+ NewCfg = ?CFG:bb_add(Cfg,Label,NewBB),
+ NewVisited = [NewInst|VisitedInstructions];
+ _->
+ {BeforeCode,AfterCode} = split_for_xsi(VisitedInstructions,[]),
+ TempVisited = BeforeCode++[XsiLink|AfterCode],
+ TempVisited2 = lists:reverse(TempVisited),
+ NewVisited = [NewInst|TempVisited2],
+ NewCfg = Cfg
+ 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),
+ case Succs of
+ [] -> %% Exit point
+ ?GRAPH:add_vertex(CFGGraph, Label, #block{type = exit}),
+ NewToBeFactorizedAcc = ToBeFactorizedAcc;
+ _ -> %% Split point
+ ?GRAPH:add_vertex(CFGGraph,Label,#block{type=not_mp,attributes={P,Succs}}),
+ NewToBeFactorizedAcc = [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) ->
+ 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,
+ NewMaps = gb_trees:enter(XsiOp,Set,Maps),
+ NewUses = Uses;
+ #temp{} ->
+ Set = case gb_trees:lookup(XsiOp,Maps) of
+ {value, V} ->
+ ?SETS:add_element(Key,V);
+ none ->
+ ?SETS:from_list([Key])
+ end,
+ NewMaps = gb_trees:enter(XsiOp,Set,Maps),
+ 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,
+ NewUses = 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,
+ NewMaps = gb_trees:enter(XsiOp,Set,Maps),
+ 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,
+ NewUses = gb_trees:enter(Pred,SSet,Uses);
+ _->
+ NewMaps = Maps,
+ NewUses = 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,
+ case Def of
+ bottom ->
+ InstToAdd = 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(),
+ InstToAdd = Move;
+ _ ->
+ InstToAdd = 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(),
+ InstToAdd = 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,
+ 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),
+ Dst = Op#bottom.var,
+ Expr2 = ?RTL:alu_dst_update(Expr,Dst),
+ Inst = manufacture_computation(Pred,Expr2,Visited),
+ Code = Insertion#insertion.code,
+ NewInsertion = Insertion#insertion{from=[{Op,Dst}|From],code=[Inst|Code]},
+ NewInsertionsAcc = 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),
+ Dst = Val,
+ NewInsertionsAcc = 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),
+ Dst = Op#bottom.var,
+ Expr2 = ?RTL:alu_dst_update(Expr,Dst),
+ Inst = manufacture_computation(Pred,Expr2,Visited),
+ NewInsertion = #insertion{from=[{Op,Dst}],code=[Inst]},
+ NewInsertionsAcc = 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),
+ Dst = Op#const_expr.var,
+ Val = Op#const_expr.value,
+ Inst = ?RTL:mk_move(Dst,Val),
+ Code = Insertion#insertion.code,
+ NewInsertion = Insertion#insertion{from=[{Op,Dst}|From],code=[Inst|Code]},
+ NewInsertionsAcc = 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),
+ Dst = Val,
+ NewInsertionsAcc = 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),
+ Dst = Op#const_expr.var,
+ Val = Op#const_expr.value,
+ Inst = ?RTL:mk_move(Dst,Val),
+ NewInsertion = #insertion{from=[{Op,Dst}],code=[Inst]},
+ NewInsertionsAcc = 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),
+ Dst = Op#eop.var,
+ Expr2 = ?RTL:alu_dst_update(Expr,Dst),
+ Inst = manufacture_computation(Pred,Expr2,Visited),
+ Code = Insertion#insertion.code,
+ NewInsertion = Insertion#insertion{from=[{Op,Dst}|From],code=[Inst|Code]},
+ NewInsertionsAcc = 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),
+ Dst = Val,
+ NewInsertionsAcc = 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),
+ Dst = Op#eop.var,
+ Expr2 = ?RTL:alu_dst_update(Expr,Dst),
+ Inst = manufacture_computation(Pred,Expr2,Visited),
+ NewInsertion = #insertion{from=[{Op,Dst}],code=[Inst]},
+ NewInsertionsAcc = 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",[]),
+ Dst = Op#temp.var,
+ NewInsertionsAcc = InsertionsAcc;
+ _ ->
+ ?pp_debug("~nBut the operand is a NOT WBA Xsi: we must make an insertion",[]),
+ Dst = ?RTL:mk_new_var(),
+ Expr2 = ?RTL:alu_dst_update(Expr,Dst),
+ Inst = manufacture_computation(Pred,Expr2,Visited),
+ Code = Insertion#insertion.code,
+ NewInsertion = Insertion#insertion{from=[{Op,Dst}|From],code=[Inst|Code]},
+ NewInsertionsAcc = 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",[]),
+ Dst = Val,
+ NewInsertionsAcc = 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",[]),
+ Dst = Op#temp.var,
+ NewInsertionsAcc = InsertionsAcc;
+ _ ->
+ ?pp_debug("~nBut the operand is a NOT WBA Xsi: we must make an insertion",[]),
+ Dst = ?RTL:mk_new_var(),
+ Expr2 = ?RTL:alu_dst_update(Expr,Dst),
+ Inst = manufacture_computation(Pred,Expr2,Visited),
+ NewInsertion = #insertion{from=[{Op,Dst}],code=[Inst]},
+ NewInsertionsAcc = 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]),
+ Dst = Op,
+ NewInsertionsAcc = 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.