%-----------------------------------------------------------------------------% % 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("\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). %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------%