Files
mercury/compiler/rl_analyse.m
Simon Taylor 18430aaef1 Aditi compilation.
Estimated hours taken: 1200

Aditi compilation.

compiler/options.m:
	The documentation for these is commented out because the Aditi
	system is not currently useful to the general public.
	--aditi: enable Aditi compilation.
	--dump-rl: write the intermediate RL to `<module>.rl_dump'.
	--dump-rl-bytecode: write a text version of the bytecodes
		to `<module>.rla'
	--aditi-only: don't produce a `.c' file.
	--filenames-from-stdin: accept a list of filenames to compile
		from stdin. This is used by the query shell.
	--optimize-rl, --optimize-rl-cse, --optimize-rl-invariants,
	--optimize-rl-index, --detect-rl-streams:
		Options to control RL optimization passes.
	--aditi-user:
		Default owner of any Aditi procedures,
		defaults to $USER or "guest".
	--generate-schemas:
		write schemas for base relations to `<module>'.base_schema
		and schemas for derived relations to `<module>'.derived_schema.
		This is used by the query shell.

compiler/handle_options.m:
	Handle the default for --aditi-user.

compiler/hlds_pred.m:
compiler/prog_data.m:
compiler/prog_io_pragma.m:
compiler/make_hlds.m:
	Add some Aditi pragma declarations - `aditi', `supp_magic', `context',
	`naive', `psn' (predicate semi-naive), `aditi_memo', `aditi_no_memo',
	`base_relation', `owner' and `index'.
	Separate out code to parse a predicate name and arity.

compiler/hlds_pred.m:
	Add predicates to identify Aditi procedures.
	Added markers `generate_inline' and `aditi_interface', which
	are used internally for Aditi code generation.
	Add an `owner' field to pred_infos, which is used for database
	security checks.
	Add a field to pred_infos to hold the list of indexes for a base
	relation.

compiler/make_hlds.m:
	Some pragmas must be exported if the corresponding predicates
	are exported, check this.
	Make sure stratification of Aditi procedures is checked.
	Predicates with a mode declaration but no type declaration
	are no longer assumed to be local.
	Set the `do_aditi_compilation' field of the module_info if there
	are any local Aditi procedures or base relations.
	Check that `--aditi' is set if Aditi compilation is required.

compiler/post_typecheck.m:
	Check that every Aditi predicate has an `aditi__state' argument,
	which is used to ensure sequencing of updates and that Aditi
	procedures are only called within transactions.

compiler/dnf.m:
	Changed the definition of disjunctive normal form slightly
	so that a call followed by some atomic goals not including
	any database calls is considered atomic. magic.m can handle
	this kind of goal, and it results in more efficient RL code.

compiler/hlds_module.m:
compiler/dependency_graph.m:
	Added dependency_graph__get_scc_entry_points which finds
	the procedures in an SCC which could be called from outside.
	Added a new field to the dependency_info, the
	aditi_dependency_ordering. This contains all Aditi SCCs of
	the original program, with multiple SCCs merged where
	possible to improve the effectiveness of differential evaluation
	and the low level RL optimizations.

compiler/hlds_module.m:
	Add a field to record whether there are any local Aditi procedures
	in the current module.
	Added versions of module_info_pred_proc_info and
	module_info_set_pred_proc_info which take a pred_proc_id,
	not a separate pred_id and proc_id.

compiler/polymorphism.m:
compiler/lambda.m:
	Make sure that predicates created for closures in Aditi procedures
	have the correct markers.

compiler/goal_util.m:
	Added goal_util__switch_to_disjunction,
	goal_util__case_to_disjunct (factored out from simplify.m)
	and goal_util__if_then_else_to_disjunction. These are
	require because supplementary magic sets can't handle
	if-then-elses or switches.

compiler/type_util.m:
	Added type_is_aditi_state/1.

compiler/mode_util.m:
	Added partition_args/5 which partitions a list of arguments
	into inputs and others.

compiler/inlining.m:
	Don't inline memoed procedures.
	Don't inline Aditi procedures into non-Aditi procedures.

compiler/intermod.m:
	Handle Aditi markers.
	Clean up handling of markers which should not appear in `.opt' files.

compiler/simplify.m:
	Export a slightly different interface for use by magic.m.
	Remove explicit quantifications where possible.
	Merge multiple nested quantifications.
	Don't report infinite recursion warnings for Aditi procedures.

compiler/prog_out.m:
	Generalised the code to output a module list to write any list.

compiler/code_gen.m:
compiler/arg_info.m:
	Don't process Aditi procedures.

compiler/mercury_compile.m:
	Call magic.m and rl_gen.m.
	Don't perform the low-level annotation passes on Aditi procedures.
	Remove calls to constraint.m - sometime soon a rewritten version
	will be called directly from deforestation.

compiler/passes_aux.m:
	Add predicates to process only non-Aditi procedures.

compiler/llds.m:
compiler/llds_out.m:
	Added new `code_addr' enum members, do_{det,semidet,nondet}_aditi_call,
	which are defined in extras/aditi/aditi.m.

compiler/call_gen.m:
	Handle generation of do_*_aditi_call.

compiler/llds_out.m:
	Write the RL code for the module as a constant char array
	in the `.c' file.

compiler/term_errors.m:
compiler/error_util.m:
	Move code to describe predicates into error_util.m
	Allow the caller to explicitly add line breaks.
	Added error_util:list_to_pieces to format a list of
	strings.
	Reordered some arguments for currying.

compiler/hlds_out.m:
	Don't try to print clauses if there are none.

runtime/mercury_init.h:
util/mkinit.c:
scripts/c2init.in:
	Added a function `mercury__load_aditi_rl_code()' to the generated
	`<module>_init.c' file which throws all the RL code for the program
	at the database. This should be called at connection time by
	`aditi__connect'.
	Added an option `--aditi' which controls the output
	`mercury__load_aditi_rl_code()'.

compiler/notes/compiler_design.html:
	Document the new files.

Mmakefile:
bindist/Mmakefile:
	Don't distribute extras/aditi yet.

New files:

compiler/magic.m:
compiler/magic_util.m:
	Supplementary magic sets transformation. Report errors
	for constructs that Aditi can't handle.

compiler/context.m:
	Supplementary context transformation.

compiler/rl_gen.m:
compiler/rl_relops.m:
	Aditi code generation.

compiler/rl_info.m:
	Code generator state.

compiler/rl.m:
	Intermediate RL representation.

compiler/rl_util:
	Predicates to collect information about RL instructions.

compiler/rl_dump.m:
	Print out the representation in rl.m.

compiler/rl_opt.m:
	Control low-level RL optimizations.

compiler/rl_block.m:
	Break a procedure into basic blocks.

compiler/rl_analyse.m:
	Generic dataflow analysis for RL procedures.

compiler/rl_liveness.m:
	Make sure all relations are initialised before used, clear
	references to relations that are no longer required.

compiler/rl_loop.m:
	Loop invariant removal.

compiler/rl_block_opt.m:
	CSE and instruction merging on basic blocks.

compiler/rl_key.m:
	Detect upper/lower bounds for which a goal could succeed.

compiler/rl_sort.m:
	Use indexing for joins and projections.
	Optimize away unnecessary sorting and indexing.

compiler/rl_stream.m:
	Detect relations which don't need to be materialised.

compiler/rl_code.m:
	RL bytecode definitions. Automatically generated from the Aditi
	header files.

compiler/rl_out.m:
compiler/rl_file.m:
	Output the RL bytecodes in binary to <module>.rlo (for use by Aditi)
	and in text to <module>.rla (for use by the RL interpreter).
	Also output the schema information if --generate-schemas is set.

compiler/rl_exprn.m:
	Generate bytecodes for join conditions.

extras/aditi/Mmakefile:
extras/aditi/aditi.m:
	Definitions of some Aditi library predicates and the
	interfacing and transaction processing code.
1998-12-06 23:49:14 +00:00

355 lines
13 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 1998 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 rl_analyse.
:- interface.
:- import_module rl_block.
:- import_module io, list, map, set, 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 globals, options.
:- import_module assoc_list, bool, relation, require, 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 =
lambda([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(
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).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%