mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-14 21:35:49 +00:00
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.
442 lines
17 KiB
Mathematica
442 lines
17 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_stream.m
|
|
% Main author: stayl
|
|
%
|
|
% The output of a relational operation can be used as a stream if it is
|
|
% used only once after it is produced and if indexing is not required.
|
|
% A stream is never stored in its entirety - it is produced one tuple at
|
|
% a time as needed.
|
|
%
|
|
% Some operations have both a stream output and one or more materialised
|
|
% outputs (union_diff, insert and project). If any of these materialised
|
|
% outputs are used before the stream output is traversed in its entirety,
|
|
% the stream output must be materialised.
|
|
%
|
|
% By default, a temporary relation should have status stream. This module
|
|
% finds temporary relations which cannot be used as streams and makes
|
|
% sure they are materialised.
|
|
%
|
|
% The algorithm used follows the chain of blocks in the procedure, dividing
|
|
% the procedure up into sections containing no back arcs in the flow graph.
|
|
% A relation which becomes live and then dies within that region only
|
|
% being used once can be turned into a stream.
|
|
%
|
|
% This pass should be run last, after rl_liveness.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module rl_stream.
|
|
|
|
:- interface.
|
|
|
|
:- import_module rl_block.
|
|
|
|
:- pred rl_stream__detect_streams(rl_opt_info, rl_opt_info).
|
|
:- mode rl_stream__detect_streams(in, out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- implementation.
|
|
|
|
:- import_module rl.
|
|
:- import_module assoc_list, bag, int, list, map, multi_map.
|
|
:- import_module relation, require, set, std_util.
|
|
|
|
:- type stream_info
|
|
---> stream_info(
|
|
set(relation_id), % must materialise rels
|
|
bag(relation_id), % use counts - must be one
|
|
% if the relation is to be
|
|
% streamed.
|
|
multi_map(relation_id, relation_id)
|
|
% aliases introduced by `ref'.
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl_stream__detect_streams -->
|
|
rl_opt_info_get_rev_block_order(RevOrder),
|
|
{ list__reverse(RevOrder, Order) },
|
|
rl_opt_info_get_input_relations(Inputs),
|
|
rl_opt_info_get_output_relations(Outputs),
|
|
rl_opt_info_get_memoed_relations(Memoed),
|
|
{ set__insert_list(Memoed, Inputs, Materialise0) },
|
|
{ set__insert_list(Materialise0, Outputs, Materialise1) },
|
|
rl_stream__detect_streams_2(Order, Materialise1, Materialise2),
|
|
{ set__to_sorted_list(Materialise2, Materialise) },
|
|
list__foldl(rl_stream__update_must_materialise, Materialise).
|
|
|
|
:- pred rl_stream__detect_streams_2(list(block_id)::in, set(relation_id)::in,
|
|
set(relation_id)::out, rl_opt_info::in, rl_opt_info::out) is det.
|
|
|
|
rl_stream__detect_streams_2([], Materialise, Materialise) --> [].
|
|
rl_stream__detect_streams_2([Block | Order0], Materialise0, Materialise) -->
|
|
{ bag__init(Uses) },
|
|
{ multi_map__init(Aliases) },
|
|
{ Info0 = stream_info(Materialise0, Uses, Aliases) },
|
|
rl_opt_info_get_flow_graph(Graph),
|
|
{ rl_stream__get_blocks_to_back_arc(Graph, [Block | Order0], Order,
|
|
[], BlockList) },
|
|
{ set__list_to_set(BlockList, BlockSet) },
|
|
rl_opt_info_get_block_map(BlockMap),
|
|
{ list__foldl(rl_stream__detect_must_materialise_rels(Graph,
|
|
BlockMap, BlockSet),
|
|
BlockList, Info0, Info1) },
|
|
{ rl_stream__detect_multiple_use_rels(Graph, BlockMap, BlockList, Info1,
|
|
Block, Info1, Info) },
|
|
{ Info = stream_info(Materialise1, _, _) },
|
|
rl_stream__detect_streams_2(Order, Materialise1, Materialise).
|
|
|
|
% Collect all blocks in the list up to the instruction which is
|
|
% the source or target of the first back arc in the graph.
|
|
:- pred rl_stream__get_blocks_to_back_arc(flow_graph::in, list(block_id)::in,
|
|
list(block_id)::out, list(block_id)::in, list(block_id)::out) is det.
|
|
|
|
rl_stream__get_blocks_to_back_arc(_, [], [], Blocks0, Blocks) :-
|
|
list__reverse(Blocks0, Blocks).
|
|
rl_stream__get_blocks_to_back_arc(Graph, [Block | Order0], Order,
|
|
Blocks0, Blocks) :-
|
|
relation__lookup_element(Graph, Block, BlockKey),
|
|
relation__lookup_to(Graph, BlockKey, CallingBlockKeys),
|
|
relation__lookup_from(Graph, BlockKey, CalledBlockKeys),
|
|
(
|
|
% Check that a calling block is not later in the sequence,
|
|
% if this is not the first block in the list to check.
|
|
Blocks0 \= [],
|
|
set__member(CallingBlockKey, CallingBlockKeys),
|
|
relation__lookup_key(Graph, CallingBlockKey, CallingBlock),
|
|
list__member(CallingBlock, Order0)
|
|
->
|
|
list__reverse(Blocks0, Blocks),
|
|
Order = [Block | Order0]
|
|
;
|
|
% Check that all called blocks are later in the sequence.
|
|
set__member(CalledBlockKey, CalledBlockKeys),
|
|
relation__lookup_key(Graph, CalledBlockKey, CalledBlock),
|
|
\+ list__member(CalledBlock, [Block | Order0])
|
|
->
|
|
list__reverse([Block | Blocks0], Blocks),
|
|
Order = Order0
|
|
;
|
|
rl_stream__get_blocks_to_back_arc(Graph, Order0, Order,
|
|
[Block | Blocks0], Blocks)
|
|
).
|
|
|
|
% Any relations which are live on entry or exit to
|
|
% this block list must be materialised.
|
|
:- pred rl_stream__detect_must_materialise_rels(flow_graph::in, block_map::in,
|
|
set(block_id)::in, block_id::in,
|
|
stream_info::in, stream_info::out) is det.
|
|
|
|
rl_stream__detect_must_materialise_rels(Graph, BlockMap,
|
|
Blocks, BlockId, Info0, Info) :-
|
|
map__lookup(BlockMap, BlockId, Block),
|
|
|
|
%
|
|
% Work out which relations are live on exit from this group of blocks.
|
|
%
|
|
relation__lookup_element(Graph, BlockId, BlockKey),
|
|
relation__lookup_to(Graph, BlockKey, CallingBlockKeys0),
|
|
set__to_sorted_list(CallingBlockKeys0, CallingBlockKeys),
|
|
relation__lookup_from(Graph, BlockKey, CalledBlockKeys0),
|
|
set__to_sorted_list(CalledBlockKeys0, CalledBlockKeys),
|
|
list__map(relation__lookup_key(Graph),
|
|
CallingBlockKeys, CallingBlocks),
|
|
set__list_to_set(CallingBlocks, CallingBlockSet),
|
|
set__difference(CallingBlockSet, Blocks, OutsideCallingBlocks0),
|
|
set__to_sorted_list(OutsideCallingBlocks0, OutsideCallingBlocks),
|
|
list__map(rl_stream__get_final_live_rels(BlockMap),
|
|
OutsideCallingBlocks, FinalLive0),
|
|
list__condense(FinalLive0, FinalLive),
|
|
rl_stream__add_must_materialise_rels(FinalLive, Info0, Info1),
|
|
|
|
%
|
|
% Work out which relations are live on entry to this group of blocks.
|
|
%
|
|
list__map(relation__lookup_key(Graph), CalledBlockKeys, CalledBlocks),
|
|
set__list_to_set(CalledBlocks, CalledBlockSet),
|
|
set__difference(CalledBlockSet, Blocks, OutsideCalledBlocks0),
|
|
set__to_sorted_list(OutsideCalledBlocks0, OutsideCalledBlocks),
|
|
list__map(rl_stream__get_initial_live_rels(BlockMap),
|
|
OutsideCalledBlocks, InitialLive0),
|
|
list__condense(InitialLive0, InitialLive),
|
|
rl_stream__add_must_materialise_rels(InitialLive, Info1, Info2),
|
|
|
|
%
|
|
% Work out which relations are required to be
|
|
% materialised by some instruction.
|
|
%
|
|
Block = block(_, Instrs, MaybeBranch, _),
|
|
AddMustMaterialiseRels =
|
|
lambda([Instr::in, StreamInfo0::in, StreamInfo::out] is det, (
|
|
rl_stream__must_materialise_rels(Instr, Rels),
|
|
rl_stream__add_must_materialise_rels(Rels,
|
|
StreamInfo0, StreamInfo)
|
|
)),
|
|
list__foldl(AddMustMaterialiseRels, Instrs, Info2, Info3),
|
|
( MaybeBranch = yes(Branch) ->
|
|
list__foldl(AddMustMaterialiseRels, [Branch], Info3, Info)
|
|
;
|
|
Info = Info3
|
|
).
|
|
|
|
:- pred rl_stream__get_initial_live_rels(block_map::in,
|
|
block_id::in, list(relation_id)::out) is det.
|
|
|
|
rl_stream__get_initial_live_rels(BlockMap, BlockId, LiveRels) :-
|
|
map__lookup(BlockMap, BlockId,
|
|
block(_, _, _, block_info(LiveRels0, _))),
|
|
set__to_sorted_list(LiveRels0, LiveRels).
|
|
|
|
:- pred rl_stream__get_final_live_rels(block_map::in,
|
|
block_id::in, list(relation_id)::out) is det.
|
|
|
|
rl_stream__get_final_live_rels(BlockMap, BlockId, LiveRels) :-
|
|
map__lookup(BlockMap, BlockId,
|
|
block(_, _, _, block_info(_, LiveRels0))),
|
|
set__to_sorted_list(LiveRels0, LiveRels).
|
|
|
|
:- pred rl_stream__detect_multiple_use_rels(flow_graph::in, block_map::in,
|
|
list(block_id)::in, stream_info::in,
|
|
block_id::in, stream_info::in, stream_info::out) is det.
|
|
|
|
rl_stream__detect_multiple_use_rels(Graph, BlockMap, BlockIds, InitialInfo,
|
|
BlockId, Info0, Info) :-
|
|
InitialInfo = stream_info(_, Uses, Aliases),
|
|
Info0 = stream_info(Materialise, _, _),
|
|
Info1 = stream_info(Materialise, Uses, Aliases),
|
|
map__lookup(BlockMap, BlockId, Block),
|
|
Block = block(_, Instrs, MaybeBranch, _),
|
|
list__foldl(rl_stream__detect_streams_instr, Instrs, Info1, Info2),
|
|
( MaybeBranch = yes(Branch) ->
|
|
rl_stream__detect_streams_instr(Branch, Info2, Info3)
|
|
;
|
|
Info3 = Info2
|
|
),
|
|
relation__lookup_element(Graph, BlockId, BlockKey),
|
|
relation__lookup_from(Graph, BlockKey, CalledBlockKeys0),
|
|
set__to_sorted_list(CalledBlockKeys0, CalledBlockKeys),
|
|
list__map(relation__lookup_key(Graph),
|
|
CalledBlockKeys, CalledBlocks),
|
|
rl_stream__inside_and_after(CalledBlocks,
|
|
BlockId, BlockIds, InsideLaterCalledBlocks),
|
|
( InsideLaterCalledBlocks = [] ->
|
|
rl_stream__end_block_list(Info3, Info)
|
|
;
|
|
list__foldl(rl_stream__detect_multiple_use_rels(Graph,
|
|
BlockMap, BlockIds, Info3),
|
|
InsideLaterCalledBlocks, Info0, Info)
|
|
).
|
|
|
|
% Find all called blocks inside the set of interest and
|
|
% after the given one -- we don't want to go back around a loop.
|
|
:- pred rl_stream__inside_and_after(list(block_id)::in, block_id::in,
|
|
list(block_id)::in, list(block_id)::out) is det.
|
|
|
|
rl_stream__inside_and_after(CalledBlocks, BlockId,
|
|
BlockIds, InsideLaterCalledBlocks) :-
|
|
(
|
|
list__nth_member_search(BlockIds, BlockId, N),
|
|
N1 is N - 1,
|
|
list__split_list(N1, BlockIds, _, AfterBlockIds0),
|
|
AfterBlockIds0 = [BlockId | AfterBlockIds]
|
|
->
|
|
list__filter(lambda([CalledBlock::in] is semidet, (
|
|
list__member(CalledBlock, AfterBlockIds)
|
|
)), CalledBlocks, InsideLaterCalledBlocks)
|
|
;
|
|
error("rl_stream__inside_and_after")
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl_stream__detect_streams_instr(rl_instruction::in,
|
|
stream_info::in, stream_info::out) is det.
|
|
|
|
rl_stream__detect_streams_instr(Instr) -->
|
|
( { Instr = ref(Output, Input) - _ } ->
|
|
rl_stream__add_alias(Output, Input)
|
|
;
|
|
{ rl__instr_relations(Instr, Inputs, _) },
|
|
rl_stream__update_counts(Inputs)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl_stream__end_block_list(stream_info::in, stream_info::out) is det.
|
|
|
|
rl_stream__end_block_list(Info0, Info) :-
|
|
Info0 = stream_info(Materialise0, Uses, Aliases),
|
|
bag__to_list_without_duplicates(Uses, UsedRels),
|
|
list__foldl(rl_stream__end_block_check_relation(Uses, Aliases),
|
|
UsedRels, Materialise0, Materialise),
|
|
Info = stream_info(Materialise, Uses, Aliases).
|
|
|
|
% Work out which relations used in this block need to be materialised.
|
|
:- pred rl_stream__end_block_check_relation(bag(relation_id)::in,
|
|
multi_map(relation_id, relation_id)::in, relation_id::in,
|
|
set(relation_id)::in, set(relation_id)::out) is det.
|
|
|
|
rl_stream__end_block_check_relation(Uses, Aliases, Relation,
|
|
Materialise0, Materialise) :-
|
|
( multi_map__search(Aliases, Relation, RelAliases) ->
|
|
Relations0 = [Relation | RelAliases]
|
|
;
|
|
Relations0 = [Relation]
|
|
),
|
|
set__list_to_set(Relations0, Relations),
|
|
set__intersect(Relations, Materialise0, Intersect),
|
|
( set__empty(Intersect) ->
|
|
set__to_sorted_list(Relations, RelationsList),
|
|
list__map(bag__count_value(Uses), RelationsList, Counts),
|
|
list__foldl(lambda([X::in, Y::in, Z::out] is det, Z is X + Y),
|
|
Counts, 0, NumUses),
|
|
( NumUses = 1 ->
|
|
Materialise = Materialise0
|
|
;
|
|
set__union(Materialise0, Relations, Materialise)
|
|
)
|
|
;
|
|
set__union(Materialise0, Relations, Materialise)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Ensure that the status of a materialised temporary is correct.
|
|
:- pred rl_stream__update_must_materialise(relation_id::in,
|
|
rl_opt_info::in, rl_opt_info::out) is det.
|
|
|
|
rl_stream__update_must_materialise(RelationId) -->
|
|
rl_opt_info_get_relation_info(RelationId, RelationInfo0),
|
|
{ RelationInfo0 = relation_info(Type0, B, C, D) },
|
|
( { Type0 = temporary(stream) } ->
|
|
rl_opt_info_set_relation_info(RelationId,
|
|
relation_info(temporary(materialised), B, C, D))
|
|
;
|
|
[]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Increment the usage counts for the list of relations.
|
|
:- pred rl_stream__update_counts(list(relation_id)::in, stream_info::in,
|
|
stream_info::out) is det.
|
|
|
|
rl_stream__update_counts(RelationIds, Info0, Info) :-
|
|
Info0 = stream_info(A, Counts0, C),
|
|
bag__insert_list(Counts0, RelationIds, Counts),
|
|
Info = stream_info(A, Counts, C).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl_stream__add_must_materialise_rels(list(relation_id)::in,
|
|
stream_info::in, stream_info::out) is det.
|
|
|
|
rl_stream__add_must_materialise_rels(Rels, Info0, Info) :-
|
|
Info0 = stream_info(Materialise0, B, C),
|
|
set__insert_list(Materialise0, Rels, Materialise),
|
|
Info = stream_info(Materialise, B, C).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl_stream__add_alias(relation_id::in, relation_id::in,
|
|
stream_info::in, stream_info::out) is det.
|
|
|
|
rl_stream__add_alias(Rel1, Rel2, Info0, Info) :-
|
|
Info0 = stream_info(A, B, Aliases0),
|
|
multi_map__set(Aliases0, Rel1, Rel2, Aliases1),
|
|
multi_map__set(Aliases1, Rel1, Rel2, Aliases),
|
|
Info = stream_info(A, B, Aliases).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Return the list of relations which the given instruction requires
|
|
% to be materialised.
|
|
:- pred rl_stream__must_materialise_rels(rl_instruction, list(relation_id)).
|
|
:- mode rl_stream__must_materialise_rels(in, out) is det.
|
|
|
|
rl_stream__must_materialise_rels(join(Output, _, _, _, _) - _, Materialise) :-
|
|
rl_stream__output_is_indexed(Output, Materialise).
|
|
rl_stream__must_materialise_rels(subtract(Output, _, _, _, _) - _,
|
|
Materialise) :-
|
|
rl_stream__output_is_indexed(Output, Materialise).
|
|
rl_stream__must_materialise_rels(difference(Output, _, _, _) - _,
|
|
Materialise) :-
|
|
rl_stream__output_is_indexed(Output, Materialise).
|
|
rl_stream__must_materialise_rels(project(Output, _, _, OtherOutputs, _) - _,
|
|
Materialise) :-
|
|
( OtherOutputs = [] ->
|
|
rl_stream__output_is_indexed(Output, Materialise)
|
|
;
|
|
% XXX The first output in this case doesn't actually have
|
|
% to be materialised, but see the comment on union_diff below
|
|
% to see why we do it anyway.
|
|
assoc_list__keys(OtherOutputs, Outputs),
|
|
list__map(rl__output_rel_relation, [Output | Outputs],
|
|
Materialise)
|
|
).
|
|
rl_stream__must_materialise_rels(union(Output, _, _) - _, Materialise) :-
|
|
rl_stream__output_is_indexed(Output, Materialise).
|
|
|
|
% XXX the difference doesn't actually have to be materialised,
|
|
% but it's a difficult case to handle because we have to be
|
|
% sure that the difference is fully looked at somewhere to
|
|
% force the update of the I/O relation, and also we need to
|
|
% be sure that this happens before the I/O relation is used.
|
|
rl_stream__must_materialise_rels(union_diff(UoOutput, DiInput, _,
|
|
output_rel(Difference, _), _, _) - _,
|
|
[UoOutput, DiInput, Difference]).
|
|
rl_stream__must_materialise_rels(insert(UoOutput, DiInput, _, _, _) - _,
|
|
[UoOutput, DiInput]).
|
|
rl_stream__must_materialise_rels(sort(Output, _, _) - _, Materialise) :-
|
|
rl_stream__output_is_indexed(Output, Materialise).
|
|
rl_stream__must_materialise_rels(unset(_) - _, []).
|
|
rl_stream__must_materialise_rels(init(output_rel(Rel, _)) - _, [Rel]).
|
|
rl_stream__must_materialise_rels(insert_tuple(Output, _, _) - _,
|
|
Materialise) :-
|
|
rl_stream__output_is_indexed(Output, Materialise).
|
|
|
|
% Indexed relations must always be materialised.
|
|
rl_stream__must_materialise_rels(add_index(output_rel(Rel, _)) - _, [Rel]).
|
|
rl_stream__must_materialise_rels(clear(Rel) - _, [Rel]).
|
|
rl_stream__must_materialise_rels(ref(_, _) - _, []).
|
|
rl_stream__must_materialise_rels(copy(output_rel(Output, _), Input) - _,
|
|
[Output, Input]).
|
|
rl_stream__must_materialise_rels(make_unique(output_rel(Output, _), Input) - _,
|
|
[Output, Input]).
|
|
rl_stream__must_materialise_rels(label(_) - _, []).
|
|
rl_stream__must_materialise_rels(conditional_goto(Cond, _) - _, Rels) :-
|
|
rl__goto_cond_relations(Cond, Rels).
|
|
rl_stream__must_materialise_rels(goto(_) - _, []).
|
|
rl_stream__must_materialise_rels(comment - _, []).
|
|
rl_stream__must_materialise_rels(aggregate(_, _, _, _) - _, []).
|
|
rl_stream__must_materialise_rels(call(_, Inputs, OutputRels, _) - _,
|
|
Materialise) :-
|
|
list__map(rl__output_rel_relation, OutputRels, Outputs),
|
|
list__append(Inputs, Outputs, Materialise).
|
|
|
|
:- pred rl_stream__outputs_are_indexed(list(output_rel)::in,
|
|
list(relation_id)::out) is det.
|
|
|
|
rl_stream__outputs_are_indexed(Outputs, Indexed) :-
|
|
list__filter_map(lambda([OutputRel::in, Output::out] is semidet, (
|
|
OutputRel = output_rel(Output, Indexes),
|
|
Indexes = [_|_]
|
|
)), Outputs, Indexed).
|
|
|
|
:- pred rl_stream__output_is_indexed(output_rel::in,
|
|
list(relation_id)::out) is det.
|
|
|
|
rl_stream__output_is_indexed(output_rel(Output, Indexes), Indexed) :-
|
|
( Indexes = [] ->
|
|
Indexed = []
|
|
;
|
|
Indexed = [Output]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|