Files
mercury/compiler/rl_analyse.m
Zoltan Somogyi 3c60c0e485 Change a bunch of modules to import only one module per line, even
Estimated hours taken: 4
Branches: main

compiler/*.m:
	Change a bunch of modules to import only one module per line, even
	from the library.

compiler/mlds_to_il.m:
compiler/mlds_to_managed.m:
	Convert these modules to our current coding style. Use state variables
	where appropriate. Use predmode declarations where possible.
2005-03-22 06:40:32 +00:00

364 lines
13 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 1998,2002-2005 University of Melbourne.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%-----------------------------------------------------------------------------%
% File: rl_analyse.m
% Main author: stayl
%
% Generic flow graph analysis for RL instructions.
% This is mostly as described in the Dragon Book, chapter 10.
%-----------------------------------------------------------------------------%
:- module aditi_backend__rl_analyse.
:- interface.
:- import_module aditi_backend__rl_block.
:- import_module io.
:- import_module list.
:- import_module map.
:- import_module set.
:- import_module std_util.
% rl_analyse(Blocks, Direction, Init, Confluence, Update, Results,
% Globals0, Globals, IO0, IO).
:- pred rl_analyse(list(block_id), rl_analysis(T, U, V), block_data_map(T, U),
block_data_map(T, U), V, V, io__state, io__state,
rl_opt_info, rl_opt_info) is det.
:- mode rl_analyse(in, rl_analysis, in, out, in, out, di, uo, in, out) is det.
:- type rl_analysis(BlockData, Info, Globals)
---> rl_analysis(
direction,
confluence(BlockData, Globals),
block_update(BlockData, Info, Globals),
equal(BlockData, Globals),
write(BlockData, Info, Globals)
).
:- inst rl_analysis
---> rl_analysis(
ground,
confluence,
block_update,
equal,
write
).
% Input and output data for each block.
:- type block_data_map(T, U) == map(block_id, block_data(T, U)).
:- type block_data(Data, Info)
---> block_data(
Data, % in value
Data, % out value
Info % data associated with the block (e.g. gen + kill sets)
).
:- mode rl_analysis == in(rl_analysis).
:- type direction
---> forward
; backward.
% Combine the information for multiple callers/callees of a block.
% The first block_id - BlockData argument pair corresponds to the
% feeder block whose information is being added.
% The second pair is for the block whose entry information is being
% computed. The maybe(BlockData) should be `no' for data to which
% nothing has been added.
% Knowing the block_ids is useful in cases where for some
% arcs only a subset of the information should be propagated.
:- type confluence(BlockData, Globals) ==
pred(pair(block_id, BlockData),
pair(block_id, maybe(BlockData)), BlockData,
Globals, Globals, rl_opt_info, rl_opt_info).
:- inst confluence == (pred(in, in, out, in, out, in, out) is det).
% Given the information at entry, compute the information at exit.
:- type block_update(BlockData, Info, Globals) ==
pred(block_id, BlockData, block_data(BlockData, Info),
block_data(BlockData, Info), Globals, Globals,
rl_opt_info, rl_opt_info).
:- inst block_update == (pred(in, in, in, out, in, out, in, out) is det).
% Do an in-in test unification.
:- type equal(BlockData, Globals) == pred(BlockData, BlockData, Globals).
:- inst equal == (pred(in, in, in) is semidet).
% Pretty print the block data for debugging.
:- type write(BlockData, Info, Globals) ==
(pred(block_data(BlockData, Info), Globals, io__state, io__state)).
:- inst write == (pred(in, in, di, uo) is det).
%-----------------------------------------------------------------------------%
% This format of data is what is described in the Dragon Book, so
% it should occur often enough to be special-cased here.
% The extra data is a pair of int_sets which correspond to the data
% "generated" and "killed" by the block.
:- type gen_kill_data == block_data(int_set, pair(int_set)).
:- type gen_kill_data_map == block_data_map(int_set, pair(int_set)).
% XXX use bit vectors.
:- type int_set == set(int).
:- pred rl_analyse__write_gen_kill_data(gen_kill_data::in, Globals::in,
io__state::di, io__state::uo) is det.
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module libs__globals.
:- import_module libs__options.
:- import_module assoc_list.
:- import_module bool.
:- import_module relation.
:- import_module require.
:- import_module string.
rl_analyse(Blocks, Analysis, BlockDataMap0, BlockDataMap,
Globals0, Globals, IO0, IO) -->
rl_opt_info_get_rev_block_order(RevOrder),
{ list__reverse(RevOrder, Order) },
{ rl_analyse__message("Initial info\n", [], IO0, IO1) },
{ rl_analyse__dump_block_data_map(Analysis, Order,
BlockDataMap0, Globals0, IO1, IO2) },
rl_analyse__to_fixpoint(Analysis, Blocks,
BlockDataMap0, BlockDataMap, Globals0, Globals, IO2, IO3),
{ rl_analyse__dump_block_data_map(Analysis, Order,
BlockDataMap, Globals, IO3, IO) }.
:- pred rl_analyse__to_fixpoint(rl_analysis(T, U, V)::rl_analysis,
list(block_id)::in, block_data_map(T, U)::in,
block_data_map(T, U)::out, V::in, V::out, io__state::di, io__state::uo,
rl_opt_info::in, rl_opt_info::out) is det.
rl_analyse__to_fixpoint(Analysis, Blocks, BlockDataMap0, BlockDataMap,
Globals0, Globals, IO0, IO) -->
{ rl_analyse__do_io(io__write_string("rl_analyse: starting new pass\n"),
IO0, IO1) },
rl_analyse__blocks(Analysis, Blocks, BlockDataMap0, BlockDataMap1,
no, Changed, Globals0, Globals1, IO1, IO2),
( { Changed = yes } ->
rl_analyse__to_fixpoint(Analysis, Blocks, BlockDataMap1,
BlockDataMap, Globals1, Globals, IO2, IO)
;
{ rl_analyse__do_io(io__write_string("finished iterating\n"),
IO2, IO) },
{ Globals = Globals1 },
{ BlockDataMap = BlockDataMap1 }
).
:- pred rl_analyse__blocks(rl_analysis(T, U, V)::rl_analysis,
list(block_id)::in, block_data_map(T, U)::in,
block_data_map(T, U)::out, bool::in, bool::out,
V::in, V::out, io__state::di, io__state::uo,
rl_opt_info::in, rl_opt_info::out) is det.
rl_analyse__blocks(_, [], Info, Info, Changed, Changed,
Globals, Globals, IO, IO) --> [].
rl_analyse__blocks(Analysis, [BlockId | BlockIds], BlockDataMap0, BlockDataMap,
Changed0, Changed, Globals0, Globals, IO0, IO) -->
rl_opt_info_get_flow_graph(FlowGraph),
{ relation__lookup_element(FlowGraph, BlockId, BlockKey) },
%
% Work out where the information flowing into the block comes from.
%
{ rl_analyse__direction(Analysis, Direction) },
{
Direction = forward,
relation__lookup_to(FlowGraph, BlockKey, PredecessorKeys0)
;
Direction = backward,
relation__lookup_from(FlowGraph, BlockKey, PredecessorKeys0)
},
{ set__to_sorted_list(PredecessorKeys0, PredecessorKeys) },
{ list__map(relation__lookup_key(FlowGraph), PredecessorKeys,
Predecessors) },
{ map__lookup(BlockDataMap0, BlockId, BlockData0) },
{ GetOutValues = (pred(Node::in, NodeAndOValue::out) is det :-
map__lookup(BlockDataMap0, Node, block_data(_, OutValue, _)),
NodeAndOValue = Node - OutValue
) },
{ list__map(GetOutValues, Predecessors, OutPredecessors) },
%
% Combine the information flowing into the block using
% the confluence operator.
%
rl_analyse__confluence_list(Analysis, OutPredecessors,
BlockId - no, _ - MaybeInValue, Globals0, Globals1),
{
MaybeInValue = yes(InValue)
;
MaybeInValue = no,
BlockData0 = block_data(InValue, _, _)
},
%
% Compute the output value from the current block given the
% input computed above.
%
rl_analyse__block_update(Analysis, BlockId, InValue,
BlockData0, BlockData, Globals1, Globals2),
{ map__det_update(BlockDataMap0, BlockId, BlockData, BlockDataMap1) },
%
% Check whether anything changed.
%
{ BlockData0 = block_data(_, OldOut, _) },
{ BlockData = block_data(_, NewOut, _) },
( { rl_analyse__equal(Analysis, OldOut, NewOut, Globals2) } ->
{ Changed1 = Changed0 },
{ IO1 = IO0 }
;
{ Changed1 = yes },
{ rl_analyse__do_io(rl_analyse__dump_changed_data(Analysis,
BlockId, BlockData0, BlockData, Globals2), IO0, IO1) }
),
rl_analyse__blocks(Analysis, BlockIds, BlockDataMap1, BlockDataMap,
Changed1, Changed, Globals2, Globals, IO1, IO).
%-----------------------------------------------------------------------------%
:- pred rl_analyse__message(string::in, list(string__poly_type)::in,
io__state::di, io__state::uo) is det.
rl_analyse__message(Msg, Fmt) -->
rl_analyse__do_io(io__format(Msg, Fmt)).
:- pred rl_analyse__do_io(pred(io__state, io__state)::in(pred(di, uo) is det),
io__state::di, io__state::uo) is det.
rl_analyse__do_io(Writer) -->
globals__io_lookup_bool_option(debug_rl_opt, Debug),
( { Debug = yes } ->
call(Writer)
;
[]
).
:- pred rl_analyse__dump_block_data_map(rl_analysis(T, U, V)::rl_analysis,
list(block_id)::in, block_data_map(T, U)::in, V::in,
io__state::di, io__state::uo) is det.
rl_analyse__dump_block_data_map(Analysis, Blocks, BlockDataMap, Globals) -->
rl_analyse__do_io(pred(di, uo) is det -->
io__write_list(Blocks, "\n",
rl_analyse__dump_block_data(Analysis,
BlockDataMap, Globals))
).
:- pred rl_analyse__dump_block_data(rl_analysis(T, U, V)::rl_analysis,
block_data_map(T, U)::in, V::in, block_id::in,
io__state::di, io__state::uo) is det.
rl_analyse__dump_block_data(Analysis, BlockDataMap, Globals, BlockId) -->
{ map__lookup(BlockDataMap, BlockId, BlockData) },
io__write_string("Block "),
io__write_int(BlockId),
io__write_string(":\n"),
rl_analyse__write(Analysis, BlockData, Globals),
io__nl.
:- pred rl_analyse__dump_changed_data(rl_analysis(T, U, V)::rl_analysis,
block_id::in, block_data(T, U)::in, block_data(T, U)::in,
V::in, io__state::di, io__state::uo) is det.
rl_analyse__dump_changed_data(Analysis, BlockId, Data0, Data, Globals) -->
io__write_string("Changed data for block "),
io__write_int(BlockId),
io__write_string(":\n"),
rl_analyse__write(Analysis, Data0, Globals),
io__write_string("\t==> "),
rl_analyse__write(Analysis, Data, Globals),
io__nl.
rl_analyse__write_gen_kill_data(block_data(In, Out, Gen - Kill), _) -->
io__write_string("<gen: ["),
rl_analyse__write_int_set(Gen),
io__write_string("] kill: ["),
rl_analyse__write_int_set(Kill),
io__write_string("] in: ["),
rl_analyse__write_int_set(In),
io__write_string("] out: ["),
rl_analyse__write_int_set(Out),
io__write_string("]>\n").
:- pred rl_analyse__write_int_set(int_set::in,
io__state::di, io__state::uo) is det.
rl_analyse__write_int_set(Set0) -->
{ set__to_sorted_list(Set0, Set) },
io__write_list(Set, ", ", io__write_int).
%-----------------------------------------------------------------------------%
:- pred rl_analyse__confluence_list(rl_analysis(T, U, V)::in(rl_analysis),
assoc_list(block_id, T)::in, pair(block_id, maybe(T))::in,
pair(block_id, maybe(T))::out, V::in, V::out,
rl_opt_info::in, rl_opt_info::out) is det.
rl_analyse__confluence_list(_, [], Value, Value, Globals, Globals) --> [].
rl_analyse__confluence_list(Analysis, [OutPredecessor | OutPredecessors],
Value0, Value, Globals0, Globals) -->
rl_analyse__confluence(Analysis, OutPredecessor, Value0, Value1,
Globals0, Globals1),
rl_analyse__confluence_list(Analysis, OutPredecessors, Value1, Value,
Globals1, Globals).
%-----------------------------------------------------------------------------%
:- pred rl_analyse__direction(rl_analysis(_, _, _), direction).
:- mode rl_analyse__direction(rl_analysis, out) is det.
% Combine the information for multiple entries to a block.
:- pred rl_analyse__confluence(rl_analysis(BlockData, _, Globals),
pair(block_id, BlockData), pair(block_id, maybe(BlockData)),
pair(block_id, maybe(BlockData)), Globals, Globals,
rl_opt_info, rl_opt_info).
:- mode rl_analyse__confluence(rl_analysis, in, in, out,
in, out, in, out) is det.
% Given the information at entry, compute the information at exit.
:- pred rl_analyse__block_update(rl_analysis(BlockData, Info, Globals),
block_id, BlockData, block_data(BlockData, Info),
block_data(BlockData, Info), Globals, Globals,
rl_opt_info, rl_opt_info).
:- mode rl_analyse__block_update(rl_analysis, in, in,
in, out, in, out, in, out) is det.
:- pred rl_analyse__equal(rl_analysis(BlockData, _, Globals),
BlockData, BlockData, Globals).
:- mode rl_analyse__equal(rl_analysis, in, in, in) is semidet.
:- pred rl_analyse__write(rl_analysis(BlockData, Info, Globals),
block_data(BlockData, Info), Globals, io__state, io__state).
:- mode rl_analyse__write(rl_analysis, in, in, di, uo) is det.
%-----------------------------------------------------------------------------%
rl_analyse__direction(rl_analysis(Dir, _, _, _, _), Dir).
rl_analyse__confluence(rl_analysis(_, Confluence, _, _, _), BlockData1,
Block - MaybeData2, Block - yes(Data), Globals0, Globals) -->
call(Confluence, BlockData1, Block - MaybeData2, Data,
Globals0, Globals).
rl_analyse__block_update(rl_analysis(_, _, Update, _, _), BlockId,
In, Data0, Data, Globals0, Globals) -->
call(Update, BlockId, In, Data0, Data, Globals0, Globals).
rl_analyse__equal(rl_analysis(_, _, _, Equal, _), Data1, Data2, Globals) :-
call(Equal, Data1, Data2, Globals).
rl_analyse__write(rl_analysis(_, _, _, _, Write), Data, Globals) -->
call(Write, Data, Globals).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%