mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-15 13:55:07 +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.
355 lines
13 KiB
Mathematica
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).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|