aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe/opt/hipe_ultra_prio.erl
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/hipe/opt/hipe_ultra_prio.erl
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/hipe/opt/hipe_ultra_prio.erl')
-rw-r--r--lib/hipe/opt/hipe_ultra_prio.erl304
1 files changed, 304 insertions, 0 deletions
diff --git a/lib/hipe/opt/hipe_ultra_prio.erl b/lib/hipe/opt/hipe_ultra_prio.erl
new file mode 100644
index 0000000000..9e2c1a0489
--- /dev/null
+++ b/lib/hipe/opt/hipe_ultra_prio.erl
@@ -0,0 +1,304 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-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%
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% PRIORITY HANDLING AND PRIORITY CALCULATION
+%%
+%% Handling of ready nodes and priorities.
+%% Priorities are mainly from the critical path. More priorities are added.
+%% * One version is adding priorities just depending on the instr, so
+%% for example loads get higher priority than stores, and ordered
+%% after reg's and offset for better cache performance.
+%% * The other version gives higher priority to a node that adds more new
+%% nodes to the ready list. This one is maybe not so effectively
+%% implemented, but was added too late for smarter solutions.
+%% One version is commented away
+
+-module(hipe_ultra_prio).
+-export([init_ready/2,
+ init_instr_prio/2,
+ %% initial_ready_set/4,
+ next_ready/7,
+ add_ready_nodes/2,
+ insert_node/3
+ ]).
+
+-include("../sparc/hipe_sparc.hrl").
+
+% At first, only nodes with no predecessors are selected.
+% - if R is empty, there is an error (unless BB itself is empty)
+
+%% Arguments : Size - size of ready-array
+%% Preds - array with number of predecessors for each node
+%% Returns : An array with list of ready-nodes for each cycle.
+
+init_ready(Size, Preds) ->
+ P = hipe_vectors:size(Preds),
+ Ready = hipe_vectors:new(Size, []),
+ R = initial_ready_set(1, P, Preds, []),
+ hipe_vectors:set(Ready, 0, R).
+
+init_instr_prio(N, DAG) ->
+ critical_path(N, DAG).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Function : initial_ready_set
+%% Argument : M - current node-index
+%% N - where to stop
+%% Preds - array with number of predecessors for each node
+%% Ready - list with ready-nodes
+%% Returns : Ready - list with ready-nodes
+%% Description : Finds all nodes with no predecessors and adds them to ready.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+initial_ready_set(M, N, Preds, Ready) ->
+ if
+ M > N ->
+ Ready;
+ true ->
+ case hipe_vectors:get(Preds, M-1) of
+ 0 ->
+ initial_ready_set(M+1, N, Preds, [M|Ready]);
+ V when is_integer(V), V > 0 ->
+ initial_ready_set(M+1, N, Preds, Ready)
+ end
+ end.
+
+%% The following handles the nodes ready to schedule:
+%% 1. select the ready queue of given cycle
+%% 2. if queue empty, return none
+%% 3. otherwise, remove entry with highest priority
+%% and return {next,Highest_Prio,NewReady}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Function : next_ready
+%% Argument : C - current cycle
+%% Ready - array with ready nodes
+%% Prio - array with cpath-priorities for all nodes
+%% Nodes - indexed list [{N, Instr}]
+%% Returns : none / {next,Highest_Prio,NewReady}
+%% Description : 1. select the ready queue of given cycle
+%% 2. if queue empty, return none
+%% 3. otherwise, remove entry with highest priority
+%% and return {next,Highest_Prio,NewReady} where Highest_Prio
+%% = Id of instr and NewReady = updated ready-array.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+next_ready(C, Ready, Prio, Nodes, DAG, Preds, Earl) ->
+ Curr = hipe_vectors:get(Ready, C-1),
+ case Curr of
+ [] ->
+ none;
+ Instrs ->
+ {BestI,RestIs} =
+ get_best_instr(Instrs, Prio, Nodes, DAG, Preds, Earl, C),
+ {next,BestI,hipe_vectors:set(Ready,C-1,RestIs)}
+ end.
+
+% next_ready(C,Ready,Prio,Nodes) ->
+% Curr = hipe_vectors:get(Ready,C-1),
+% case Curr of
+% [] ->
+% none;
+% Instrs ->
+% {BestInstr,RestInstrs} = get_best_instr(Instrs, Prio, Nodes),
+% {next,BestInstr,hipe_vectors:set(Ready,C-1,RestInstrs)}
+% end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Function : get_best_instr
+%% Argument : Instrs - list of node-id's
+%% Prio - array with cpath-priorities for the nodes
+%% Nodes - indexed list [{Id, Instr}]
+%% Returns : {BestSoFar, Rest} - Id of best instr and the rest of id's
+%% Description : Returns the id of the instr that is the best choice.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+get_best_instr([Instr|Instrs], Prio, Nodes, DAG, Preds, Earl, C) ->
+ get_best_instr(Instrs, [], Instr, Prio, Nodes, DAG, Preds, Earl, C).
+
+get_best_instr([], Rest, BestSoFar, _Prio, _Nodes, _DAG, _Preds, _Earl, _C) ->
+ {BestSoFar, Rest};
+get_best_instr([Instr|Instrs], PassedInstrs, BestSoFar, Prio, Nodes,
+ DAG, Preds, Earl, C) ->
+ case better(Instr, BestSoFar, Prio, Nodes, DAG, Preds, Earl, C) of
+ true ->
+ get_best_instr(Instrs, [BestSoFar|PassedInstrs],
+ Instr, Prio, Nodes, DAG, Preds, Earl, C);
+ false ->
+ get_best_instr(Instrs, [Instr|PassedInstrs], BestSoFar, Prio,
+ Nodes, DAG, Preds, Earl, C)
+ end.
+
+% get_best_instr([Instr|Instrs], Prio, Nodes) ->
+% get_best_instr(Instrs, [], Instr, Prio, Nodes).
+
+% get_best_instr([], Rest, BestSoFar, Prio, Nodes) -> {BestSoFar, Rest};
+% get_best_instr([Instr|Instrs], PassedInstrs, BestSoFar, Prio, Nodes) ->
+% case better(Instr, BestSoFar, Prio, Nodes) of
+% true ->
+% get_best_instr(Instrs, [BestSoFar|PassedInstrs],
+% Instr, Prio, Nodes);
+% false ->
+% get_best_instr(Instrs, [Instr|PassedInstrs],BestSoFar, Prio, Nodes)
+% end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Function : better
+%% Argument : Instr1 - Id of instr 1
+%% Instr2 - Id of instr 2
+%% Prio - array with cpath-priorities for the nodes
+%% Nodes - indexed list [{Id, Instr}]
+%% Returns : true if Instr1 has higher priority than Instr2
+%% Description : Checks if Instr1 is a better choice than Instr2 for scheduling
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+better(Instr1, Instr2, Prio, Nodes, DAG, Preds, Earl, C) ->
+ better_hlp(priority(Instr1, Prio, Nodes, DAG, Preds, Earl, C),
+ priority(Instr2, Prio, Nodes, DAG, Preds, Earl, C)).
+
+better_hlp([], []) -> false;
+better_hlp([], [_|_]) -> false;
+better_hlp([_|_], []) -> true;
+better_hlp([X|Xs], [Y|Ys]) -> (X > Y) or ((X =:= Y) and better_hlp(Xs,Ys)).
+
+%%
+%% Returns the instr corresponding to id
+%%
+get_instr(InstrId, [{InstrId,Instr}|_]) -> Instr;
+get_instr(InstrId, [_|Xs]) -> get_instr(InstrId, Xs).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Function : priority
+%% Argument : InstrId - Id
+%% Prio - array with cpath-priorities for the nodes
+%% Nodes - indexed list [{Id, Instr}]
+%% Returns : PrioList - list of priorities [MostSignificant, LessSign, ...]
+%% Description : Returns a list of priorities where the first element is the
+%% cpath-priority and the rest are added depending on what kind
+%% of instr it is. Used to order loads/stores sequentially and
+%% there is possibility to add whatever stuff...
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+priority(InstrId, Prio, Nodes, DAG, Preds, Earl, C) ->
+ {ReadyNodes,_,_,_} = hipe_schedule:delete_node(C,InstrId,DAG,Preds,Earl),
+ Instr = get_instr(InstrId, Nodes),
+ Prio1 = hipe_vectors:get(Prio, InstrId-1),
+ Prio2 = length(ReadyNodes),
+ PrioRest =
+ case Instr of
+ #load_atom{} ->
+ [3];
+ #move{} ->
+ [3];
+ #load{} ->
+ Src = hipe_sparc:load_src(Instr),
+ Off = hipe_sparc:load_off(Instr),
+ case hipe_sparc:is_reg(Off) of
+ false -> [3,
+ -(hipe_sparc:reg_nr(Src)),
+ -(hipe_sparc:imm_value(Off))];
+ true -> [1]
+ end;
+ #store{} ->
+ Src = hipe_sparc:store_dest(Instr),
+ Off = hipe_sparc:store_off(Instr),
+ case hipe_sparc:is_reg(Off) of
+ false -> [2,
+ -(hipe_sparc:reg_nr(Src)),
+ -(hipe_sparc:imm_value(Off))];
+ true -> [1]
+ end;
+ _ -> [0]
+ end,
+ [Prio1,Prio2|PrioRest].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Function : add_ready_nodes
+%% Argument : Nodes - list of [{Cycle,Id}]
+%% Ready - array of ready nodes for all cycles
+%% Returns : NewReady - updated ready-array
+%% Description : Gets a list of instrs and adds them to the ready-array
+%% to the corresponding cycle.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+add_ready_nodes([], Ready) -> Ready;
+add_ready_nodes([{C,I}|Xs], Ready) ->
+ add_ready_nodes(Xs, insert_node(C, I, Ready)).
+
+insert_node(C, I, Ready) ->
+ Old = hipe_vectors:get(Ready, C-1),
+ hipe_vectors:set(Ready, C-1, [I|Old]).
+
+%%
+%% Computes the latency for the "most expensive" way through the graph
+%% for all nodes. Returns an array of priorities for all nodes.
+%%
+critical_path(N, DAG) ->
+ critical_path(1, N, DAG, hipe_vectors:new(N, -1)).
+
+critical_path(M, N, DAG, Prio) ->
+ if
+ M > N ->
+ Prio;
+ true ->
+ critical_path(M+1, N, DAG, cpath(M, DAG, Prio))
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Function : cpath
+%% Argument : M - current node id
+%% DAG - the dependence graph
+%% Prio - array of priorities for all nodes
+%% Returns : Prio - updated prio array
+%% Description : If node has prio -1, it has not been visited
+%% - otherwise, compute priority as max of priorities of
+%% successors (+ latency)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+cpath(M, DAG, Prio) ->
+ InitPrio = hipe_vectors:get(Prio, M-1),
+ if
+ InitPrio =:= -1 ->
+ cpath_node(M, DAG, Prio);
+ true ->
+ Prio
+ end.
+
+cpath_node(N, DAG, Prio) ->
+ SuccL = dag_succ(DAG, N),
+ {Max, NewPrio} = cpath_succ(SuccL, DAG, Prio),
+ hipe_vectors:set(NewPrio, N-1, Max).
+
+cpath_succ(SuccL, DAG, Prio) ->
+ cpath_succ(SuccL, DAG, Prio, 0).
+
+%% performs an unnecessary lookup of priority of Succ, but that might
+%% not be such a big deal
+
+cpath_succ([], _DAG, Prio, NodePrio) -> {NodePrio,Prio};
+cpath_succ([{Lat,Succ}|Xs], DAG, Prio, NodePrio) ->
+ NewPrio = cpath(Succ, DAG, Prio),
+ NewNodePrio = erlang:max(hipe_vectors:get(NewPrio, Succ - 1) + Lat, NodePrio),
+ cpath_succ(Xs, DAG, NewPrio, NewNodePrio).
+
+dag_succ(DAG, N) when is_integer(N) ->
+ hipe_vectors:get(DAG, N-1).
+