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.
643 lines
19 KiB
Mathematica
643 lines
19 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.m
|
|
% Main author: stayl
|
|
%
|
|
% Intermediate form used for optimization of Aditi-RL code.
|
|
%
|
|
% Generated by rl_gen.m.
|
|
% Human readable debugging output by rl_dump.m.
|
|
% Output to RL bytecodes by rl_out.m.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
:- module rl.
|
|
|
|
:- interface.
|
|
|
|
:- import_module hlds_data, hlds_goal, hlds_module, hlds_pred.
|
|
:- import_module instmap, prog_data.
|
|
:- import_module assoc_list, list, std_util, map, set.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type rl_code == list(rl_proc).
|
|
|
|
:- type rl_proc
|
|
---> rl_proc(
|
|
rl_proc_name,
|
|
list(relation_id), % input argument relations
|
|
list(relation_id), % output argument relations
|
|
set(relation_id), % memoed relations
|
|
relation_info_map, % all relations used by the procedure
|
|
list(rl_instruction),
|
|
list(pred_proc_id) % list of Mercury procedures contained
|
|
% in this RL procedure
|
|
).
|
|
|
|
:- type rl_proc_name
|
|
---> rl_proc_name(
|
|
string, % user
|
|
string, % module
|
|
string, % name
|
|
int % arity
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type relation_id == int.
|
|
|
|
:- type relation_info_map == map(relation_id, relation_info).
|
|
|
|
:- type relation_info
|
|
---> relation_info(
|
|
relation_type,
|
|
list(type), % schema
|
|
list(index_spec),
|
|
% Only used for base relations - other relations
|
|
% may have different indexes at different times.
|
|
string % name
|
|
).
|
|
|
|
:- type relation_type
|
|
---> permanent(pred_proc_id)
|
|
; temporary(relation_state).
|
|
|
|
% It may be possible that we only want to materialise a relation
|
|
% along certain branches. That should be fairly simple to fix later
|
|
% if it is necessary.
|
|
:- type relation_state
|
|
---> materialised
|
|
; stream.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type index_spec
|
|
---> index_spec(
|
|
index_type,
|
|
list(int) % which attributes are being indexed on.
|
|
).
|
|
|
|
% Hash indexes?
|
|
:- type index_type
|
|
---> unique_B_tree
|
|
; non_unique_B_tree.
|
|
|
|
% A key range gives an upper and lower bound for the part of the
|
|
% indexed relation to search. For example, a simple B-tree join
|
|
% algorithm takes a tuple from first relation and uses it to build
|
|
% a key-range for the (indexed) second relation. The join condition
|
|
% is then applied to the tuple from the first relation and every tuple
|
|
% in the second which falls within the key range.
|
|
:- type key_range
|
|
---> key_range(
|
|
bounding_tuple, % lower bound
|
|
bounding_tuple, % upper bound
|
|
maybe(list(type)), % schema of the tuple used to generate
|
|
% the key range - there isn't one
|
|
% for selects.
|
|
list(type) % schema of the tuple used to search
|
|
% the B-tree index
|
|
).
|
|
|
|
:- type bounding_tuple
|
|
---> infinity % -infinity for lower bound,
|
|
% +infinity for upper bound
|
|
; bound(
|
|
assoc_list(int, key_attr)
|
|
% attributes of the key tuple, the
|
|
% associated integer is the index
|
|
% in a full tuple for that index
|
|
% attribute.
|
|
)
|
|
.
|
|
|
|
:- type key_attr
|
|
---> functor(cons_id, (type), list(key_attr))
|
|
; infinity % -infinity for lower bound,
|
|
% +infinity for upper
|
|
% This is currently not supported,
|
|
% since there may not be a way to
|
|
% construct a term representing
|
|
% infinity.
|
|
; input_field(int)
|
|
.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% instruction and a comment.
|
|
:- type rl_instruction == pair(rl_instr, string).
|
|
|
|
:- type rl_instr
|
|
--->
|
|
join(
|
|
output_rel, % output
|
|
relation_id, % input 1
|
|
relation_id, % input 2
|
|
join_type,
|
|
rl_goal % join condition
|
|
)
|
|
;
|
|
subtract( % output = input 1 - input 2
|
|
output_rel, % output
|
|
relation_id, % input 1
|
|
relation_id, % input 2
|
|
subtract_type,
|
|
rl_goal % subtraction condition
|
|
)
|
|
;
|
|
% A difference is just a special case of subtract.
|
|
% The inputs must be sorted and have the same schema.
|
|
difference( % output = input 1 - input 2
|
|
output_rel, % output
|
|
relation_id, % input 1
|
|
relation_id, % input 2
|
|
difference_type
|
|
)
|
|
;
|
|
% A projection may have any number of output relations to
|
|
% avoid multiple traversals over the input relation.
|
|
% This also does selection - the expressions are allowed to
|
|
% fail.
|
|
% All but one of the outputs must be materialised - at the
|
|
% moment we materialise them all because it is difficult
|
|
% to ensure correctness for streams with side-effects.
|
|
project(
|
|
output_rel, % output (may be a stream)
|
|
relation_id, % input
|
|
rl_goal, % projection expression for
|
|
% stream output
|
|
assoc_list(output_rel, rl_goal),
|
|
% other outputs (materialised)
|
|
project_type
|
|
)
|
|
;
|
|
union(
|
|
output_rel, % output
|
|
list(relation_id), % inputs
|
|
union_type
|
|
)
|
|
;
|
|
% Output = Input1 U Input2, Difference = Input1 - Input2
|
|
% Input1 must have a B-tree index, and is destructively
|
|
% updated to create Output.
|
|
union_diff(
|
|
relation_id, % output (uo) (same indexes as input 1)
|
|
relation_id, % input 1 (di)
|
|
relation_id, % input 2 (in)
|
|
output_rel, % difference (out)
|
|
index_spec,
|
|
maybe(output_rel)
|
|
% Used by rl_liveness.m to make sure that
|
|
% the di input has a single reference. The
|
|
% relation_id is used to hold a copy of the
|
|
% di relation if required. The indexes should
|
|
% be added to the copy if it is made.
|
|
)
|
|
;
|
|
% Insert a relation into another relation.
|
|
% The input relation is destructively updated.
|
|
insert(
|
|
relation_id, % output (uo) (same indexes as di input)
|
|
relation_id, % relation to be inserted into (di)
|
|
relation_id, % relation to insert (in)
|
|
insert_type,
|
|
maybe(output_rel)
|
|
% Used by rl_liveness.m to make sure that
|
|
% the di input has a single reference. The
|
|
% relation_id is used to hold a copy of the
|
|
% di relation if required. The indexes should
|
|
% be added to the copy if it is made.
|
|
)
|
|
;
|
|
sort(
|
|
output_rel, % output
|
|
relation_id, % input
|
|
sort_attrs % attributes to sort on
|
|
)
|
|
;
|
|
% Make the output variable refer to the same relation
|
|
% as the input without copying.
|
|
ref(
|
|
relation_id, % output
|
|
relation_id % input
|
|
)
|
|
;
|
|
% Make a copy of the input relation, making sure the
|
|
% output has the given set of indexes.
|
|
% This could be a bit slow, because the system can't just
|
|
% copy the files, but has to do a full
|
|
copy(
|
|
output_rel, % output
|
|
relation_id % input
|
|
)
|
|
;
|
|
% If there are multiple references to the input, copy the
|
|
% input to the output, otherwise make the output a reference
|
|
% to the input. To introduce this, the compiler must know that
|
|
% there are no later references in the code to the input
|
|
% relation.
|
|
% I'm not 100% sure that the reference counts maintained
|
|
% by Aditi can be used in this way - currently we always
|
|
% do the copy.
|
|
% Make sure the output has the given set of indexes, even
|
|
% if it isn't copied.
|
|
make_unique(
|
|
output_rel, % output
|
|
relation_id % input
|
|
)
|
|
;
|
|
% Create an empty relation.
|
|
init(output_rel)
|
|
;
|
|
% add a tuple to a relation.
|
|
insert_tuple(
|
|
output_rel, % output
|
|
relation_id, % input
|
|
rl_goal
|
|
)
|
|
;
|
|
% call an RL procedure
|
|
call(
|
|
rl_proc_name, % called procedure
|
|
list(relation_id), % input argument relations
|
|
list(output_rel), % output argument relations
|
|
set(relation_id) % subset of the inputs which
|
|
% must be saved across the call,
|
|
% filled in by rl_liveness.m.
|
|
)
|
|
;
|
|
aggregate(
|
|
output_rel, % output relation
|
|
relation_id, % input relation
|
|
pred_proc_id, % predicate to produce the
|
|
% initial accumulator for
|
|
% each group
|
|
pred_proc_id % predicate to update the
|
|
% accumulator for each tuple.
|
|
)
|
|
;
|
|
% Make sure the relation has the given index.
|
|
% We don't include a remove_index operation because it
|
|
% would be very expensive and probably not very useful.
|
|
add_index(output_rel)
|
|
;
|
|
% Empty a relation. This will be expensive for permanent
|
|
% relations due to logging.
|
|
clear(relation_id)
|
|
;
|
|
% Drop a pointer to a temporary relation. The relation
|
|
% is left unchanged, but may be garbage collected if
|
|
% there are no references to it.
|
|
unset(relation_id)
|
|
;
|
|
label(label_id)
|
|
;
|
|
conditional_goto(goto_cond, label_id)
|
|
;
|
|
goto(label_id)
|
|
;
|
|
comment
|
|
.
|
|
|
|
% An output relation first clears the initial contents of the
|
|
% relation, then initialises the relation with the given set
|
|
% of indexes.
|
|
:- type output_rel
|
|
---> output_rel(
|
|
relation_id,
|
|
list(index_spec)
|
|
).
|
|
|
|
:- type goto_cond
|
|
---> empty(relation_id)
|
|
; and(goto_cond, goto_cond)
|
|
; or(goto_cond, goto_cond)
|
|
; not(goto_cond).
|
|
|
|
:- type join_type
|
|
---> nested_loop
|
|
; sort_merge(sort_spec, sort_spec)
|
|
; index(index_spec, key_range)
|
|
% The second relation is indexed.
|
|
% Each tuple in the first relation
|
|
% is used to create a key range
|
|
% for accessing the second. The goal
|
|
% builds the lower and upper bounds
|
|
% on the key range from the input
|
|
% tuple from the first relation.
|
|
; cross
|
|
; semi % The output tuple is copied from the
|
|
% first input tuple. An output projection
|
|
% must be done as a separate operation.
|
|
.
|
|
|
|
:- type subtract_type
|
|
---> nested_loop
|
|
; sort_merge(sort_spec, sort_spec)
|
|
; index(index_spec, key_range)
|
|
.
|
|
|
|
:- type difference_type
|
|
---> sort_merge(sort_spec)
|
|
.
|
|
|
|
:- type project_type
|
|
---> filter
|
|
; index(index_spec, key_range)
|
|
.
|
|
|
|
:- type union_type
|
|
---> sort_merge(sort_spec)
|
|
.
|
|
|
|
:- type insert_type
|
|
---> append
|
|
; index(index_spec).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type sort_spec
|
|
---> sort_var(int) % Some operations, such as union,
|
|
% expect their inputs to be sorted
|
|
% on all attributes, but don't care
|
|
% in which order or direction.
|
|
; attributes(sort_attrs)
|
|
% Sort on the given attributes.
|
|
.
|
|
|
|
:- type sort_attrs == assoc_list(int, sort_dir).
|
|
|
|
:- type sort_dir
|
|
---> ascending
|
|
; descending
|
|
.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% We delay converting join conditions to the lower level representation
|
|
% for as long as possible because they are easier to deal with in
|
|
% hlds_goal form.
|
|
:- type rl_goal
|
|
---> rl_goal(
|
|
maybe(pred_proc_id),
|
|
% Predicate from which the expression was
|
|
% taken - used to avoid unnecessarily merging
|
|
% varsets. Should be `no' if the varset
|
|
% contains vars from multiple procs.
|
|
prog_varset,
|
|
map(prog_var, type),
|
|
instmap, % instmap before goal
|
|
rl_goal_inputs,
|
|
rl_goal_outputs,
|
|
list(hlds_goal),
|
|
list(rl_var_bounds)
|
|
).
|
|
|
|
:- type rl_goal_inputs
|
|
---> no_inputs
|
|
; one_input(list(prog_var))
|
|
; two_inputs(list(prog_var), list(prog_var))
|
|
.
|
|
|
|
:- type rl_goal_outputs == maybe(list(prog_var)).
|
|
|
|
% A key_term is an intermediate form of a key_attr which keeps
|
|
% aliasing information. This can be converted into a key_range
|
|
% later. The set of variables attached to each node is the
|
|
% set of all variables in the goal which were found by rl_key.m
|
|
% to have that value.
|
|
:- type key_term == pair(key_term_node, set(prog_var)).
|
|
:- type key_term_node
|
|
---> functor(cons_id, (type), list(key_term))
|
|
; var
|
|
.
|
|
|
|
:- type rl_var_bounds == map(prog_var, pair(key_term)).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type label_id == int.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl__default_temporary_state(module_info::in,
|
|
relation_state::out) is det.
|
|
|
|
% rl__instr_relations(Instr, InputRels, OutputRels).
|
|
:- pred rl__instr_relations(rl_instruction::in,
|
|
list(relation_id)::out, list(relation_id)::out) is det.
|
|
|
|
% Return all relations referenced by a goto condition.
|
|
:- pred rl__goto_cond_relations(goto_cond::in,
|
|
list(relation_id)::out) is det.
|
|
|
|
% Is the instructions a label, goto or conditional goto.
|
|
:- pred rl__instr_ends_block(rl_instruction).
|
|
:- mode rl__instr_ends_block(in) is semidet.
|
|
|
|
% Strip off the index specification from an output relation.
|
|
:- pred rl__output_rel_relation(output_rel::in, relation_id::out) is det.
|
|
|
|
% Get a sort specification sorting ascending on all attributes.
|
|
:- pred rl__ascending_sort_spec(list(type)::in, sort_attrs::out) is det.
|
|
|
|
% Get a list of all attributes for a given schema.
|
|
:- pred rl__attr_list(list(T)::in, list(int)::out) is det.
|
|
|
|
% Succeed if the goal contain any of the variables corresponding
|
|
% to the attributes of the given input tuple.
|
|
:- pred rl__goal_is_independent_of_input(tuple_num::in,
|
|
rl_goal::in, rl_goal::out) is semidet.
|
|
|
|
% Swap the inputs of a goal such as a join condition which
|
|
% as two input relations.
|
|
:- pred rl__swap_goal_inputs(rl_goal::in, rl_goal::out) is det.
|
|
|
|
% Succeed if the goal produces an output tuple.
|
|
:- pred rl__goal_produces_tuple(rl_goal::in) is semidet.
|
|
|
|
:- type tuple_num
|
|
---> one
|
|
; two
|
|
.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl__proc_name_to_string(rl_proc_name::in, string::out) is det.
|
|
:- pred rl__label_id_to_string(label_id::in, string::out) is det.
|
|
:- pred rl__relation_id_to_string(relation_id::in, string::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- implementation.
|
|
|
|
:- import_module globals, options.
|
|
:- import_module bool, int, require, string.
|
|
|
|
rl__default_temporary_state(ModuleInfo, TmpState) :-
|
|
module_info_globals(ModuleInfo, Globals),
|
|
globals__lookup_bool_option(Globals, detect_rl_streams, Streams),
|
|
(
|
|
Streams = yes,
|
|
TmpState = stream
|
|
;
|
|
Streams = no,
|
|
% We have to assume that everything must be materialised.
|
|
TmpState = materialised
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl__instr_relations(join(output_rel(Output, _), Input1, Input2, _, _) - _,
|
|
[Input1, Input2], [Output]).
|
|
rl__instr_relations(subtract(output_rel(Output, _),
|
|
Input1, Input2, _, _) - _, [Input1, Input2], [Output]).
|
|
rl__instr_relations(difference(output_rel(Output, _),
|
|
Input1, Input2, _) - _, [Input1, Input2], [Output]).
|
|
rl__instr_relations(project(OutputRel,
|
|
Input, _, OtherOutputRels, _) - _,
|
|
[Input], Outputs) :-
|
|
assoc_list__keys(OtherOutputRels, OutputRels),
|
|
list__map(rl__output_rel_relation,
|
|
[OutputRel | OutputRels], Outputs).
|
|
rl__instr_relations(union(OutputRel, Inputs, _) - _, Inputs, [Output]) :-
|
|
rl__output_rel_relation(OutputRel, Output).
|
|
rl__instr_relations(union_diff(UoOutput, DiInput, Input,
|
|
output_rel(Diff, _), _, _) - _,
|
|
[DiInput, Input], [UoOutput, Diff]).
|
|
rl__instr_relations(insert(DiOutput, DiInput, Input, _, _) - _,
|
|
[DiInput, Input], [DiOutput]).
|
|
rl__instr_relations(sort(output_rel(Output, _), Input, _) - _,
|
|
[Input], [Output]).
|
|
rl__instr_relations(init(output_rel(Rel, _)) - _, [], [Rel]).
|
|
rl__instr_relations(insert_tuple(output_rel(Output, _), Input, _) - _,
|
|
[Input], [Output]).
|
|
rl__instr_relations(add_index(output_rel(Rel, _)) - _, [], [Rel]).
|
|
rl__instr_relations(clear(Rel) - _, [], [Rel]).
|
|
rl__instr_relations(unset(Rel) - _, [], [Rel]).
|
|
rl__instr_relations(label(_) - _, [], []).
|
|
rl__instr_relations(goto(_) - _, [], []).
|
|
rl__instr_relations(comment - _, [], []).
|
|
rl__instr_relations(conditional_goto(Cond, _) - _, Inputs, []) :-
|
|
rl__goto_cond_relations(Cond, Inputs).
|
|
rl__instr_relations(ref(Output, Input) - _, [Input], [Output]).
|
|
rl__instr_relations(copy(output_rel(Output, _), Input) - _,
|
|
[Input], [Output]).
|
|
rl__instr_relations(make_unique(output_rel(Output, _), Input) - _,
|
|
[Input], [Output]).
|
|
rl__instr_relations(aggregate(output_rel(Output, _), Input, _, _) - _,
|
|
[Input], [Output]).
|
|
rl__instr_relations(call(_, Inputs, OutputRels, _) - _,
|
|
Inputs, Outputs) :-
|
|
list__map(rl__output_rel_relation, OutputRels, Outputs).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl__instr_ends_block(goto(_) - _).
|
|
rl__instr_ends_block(label(_) - _).
|
|
rl__instr_ends_block(conditional_goto(_, _) - _).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl__output_rel_relation(output_rel(Output, _), Output).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl__goto_cond_relations(empty(Rel), [Rel]).
|
|
rl__goto_cond_relations(and(Cond1, Cond2), Rels) :-
|
|
rl__goto_cond_relations(Cond1, Rels1),
|
|
rl__goto_cond_relations(Cond2, Rels2),
|
|
list__append(Rels1, Rels2, Rels).
|
|
rl__goto_cond_relations(or(Cond1, Cond2), Rels) :-
|
|
rl__goto_cond_relations(Cond1, Rels1),
|
|
rl__goto_cond_relations(Cond2, Rels2),
|
|
list__append(Rels1, Rels2, Rels).
|
|
rl__goto_cond_relations(not(Cond), Rels) :-
|
|
rl__goto_cond_relations(Cond, Rels).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl__ascending_sort_spec(Schema, Attrs) :-
|
|
GetAttr =
|
|
lambda([_::in, Attr::out, Index0::in, Index::out] is det, (
|
|
Attr = Index0 - ascending,
|
|
Index is Index0 + 1
|
|
)),
|
|
list__map_foldl(GetAttr, Schema, Attrs, 0, _).
|
|
|
|
rl__attr_list(Schema, Attrs) :-
|
|
rl__attr_list_2(0, Schema, Attrs).
|
|
|
|
:- pred rl__attr_list_2(int::in, list(T)::in,
|
|
list(int)::out) is det.
|
|
|
|
rl__attr_list_2(_, [], []).
|
|
rl__attr_list_2(Index, [_ | Types], [Index | Attrs]) :-
|
|
NextIndex is Index + 1,
|
|
rl__attr_list_2(NextIndex, Types, Attrs).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl__goal_is_independent_of_input(InputNo, RLGoal0, RLGoal) :-
|
|
RLGoal0 = rl_goal(A, B, C, D, Inputs0, MaybeOutputs, Goals, H),
|
|
rl__select_input_args(InputNo, Inputs0, Inputs, InputArgs),
|
|
set__list_to_set(InputArgs, InputArgSet),
|
|
\+ (
|
|
MaybeOutputs = yes(Outputs),
|
|
set__list_to_set(Outputs, OutputSet),
|
|
set__intersect(OutputSet, InputArgSet, OutputIntersection),
|
|
\+ set__empty(OutputIntersection)
|
|
),
|
|
\+ (
|
|
list__member(Goal, Goals),
|
|
Goal = _ - GoalInfo,
|
|
goal_info_get_nonlocals(GoalInfo, NonLocals),
|
|
set__intersect(NonLocals, InputArgSet, Intersection),
|
|
\+ set__empty(Intersection)
|
|
),
|
|
RLGoal = rl_goal(A, B, C, D, Inputs, MaybeOutputs, Goals, H).
|
|
|
|
:- pred rl__select_input_args(tuple_num::in, rl_goal_inputs::in,
|
|
rl_goal_inputs::out, list(prog_var)::out) is det.
|
|
|
|
rl__select_input_args(_, no_inputs, _, _) :-
|
|
error("rl__select_input_args").
|
|
rl__select_input_args(one, one_input(Args), no_inputs, Args).
|
|
rl__select_input_args(two, one_input(_), _, _) :-
|
|
error("rl__select_input_args").
|
|
rl__select_input_args(one, two_inputs(Args, Args2),
|
|
one_input(Args2), Args).
|
|
rl__select_input_args(two, two_inputs(Args1, Args),
|
|
one_input(Args1), Args).
|
|
|
|
rl__swap_goal_inputs(RLGoal0, RLGoal) :-
|
|
RLGoal0 = rl_goal(A, B, C, D, Inputs0, F, G, H),
|
|
( Inputs0 = two_inputs(Inputs1, Inputs2) ->
|
|
RLGoal = rl_goal(A, B, C, D, two_inputs(Inputs2, Inputs1),
|
|
F, G, H)
|
|
;
|
|
error("rl__swap_inputs: goal does not have two inputs to swap")
|
|
).
|
|
|
|
rl__goal_produces_tuple(RLGoal) :-
|
|
RLGoal = rl_goal(_, _, _, _, _, yes(_), _, _).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl__proc_name_to_string(rl_proc_name(User, Module, Pred, Arity), Str) :-
|
|
string__int_to_string(Arity, ArStr),
|
|
string__append_list([User, "/", Module, "/", Pred, "/", ArStr], Str).
|
|
|
|
rl__label_id_to_string(Label, Str) :-
|
|
string__int_to_string(Label, Str0),
|
|
string__append("label", Str0, Str).
|
|
|
|
rl__relation_id_to_string(RelationId, Str) :-
|
|
string__int_to_string(RelationId, Str0),
|
|
string__append("Rel", Str0, Str).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|