mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-14 13:23:53 +00:00
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.
364 lines
13 KiB
Mathematica
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).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|