mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 01:13:30 +00:00
The parts of the compiler that run before the HLDS is constructed used to use
a raw list of items to represent source files (.m), interface files (.int0,
.int3, .int2 and .int) and optimization files (.opt, and .trans_opt).
These lists had structure, but this structure was implicit, not explicit,
and its invariants were never really documented.
This diff changes that. It replaces the item list with FIVE separate types.
Three of these each represent the unprocessed content of one file:
- parse_tree_int represents the contents of one interface file;
- parse_tree_opt represents the contents of one optimization file;
- parse_tree_src represents the contents of one source file.
Two of these each represent the processed contents of one or more files:
- raw_compilation_unit represents the contents of one module in a source file.
(The source file may contain several nested modules; the compilation unit
represents just one.)
- aug_compilation_unit represents the contents of one module in a source file,
just like raw_compilation_unit, but it is augmented with the contents of the
interface and optimization files of the other modules imported (directly or
indirectly) by the original module.
These five separate concepts all used to be represented by the same type,
list(item), but different invariants applied to the structure of those lists.
The most important of those invariants at least are now explicit in the types.
I think it is entirely possible that there are other invariants I haven't
discovered and documented (for example, .int3 files must have stricter
invariants on what can appear in them than .int files), but discovering
and documenting these should be MUCH easier after this change.
I have marked many further opportunities for improvements with "XXX ITEM_LIST".
Some of these include moving code between modules, and the creation of new
modules. However, I have left acting on those XXXs until later, in order to
keep the size of this diff down as much as possible, for easier reviewing.
compiler/prog_item.m:
Define the five new AST types described above, and utility predicates
that operate on them.
In the rest of this change, I tried, as much as possible, to change
predicates that used to take item lists as arguments to make them change
one of these types instead. In many cases, this required putting
the argument lists of those predicates into a more consistent order.
(Often, predicates that operated on the contents of the module
took the name of the module and the list of items in the module
not just as separate arguments, but as separate arguments that
weren't even next to each other.)
Define types that identify the different kinds of interface and
optimization files (.int, .int2 etc). These replace the string suffixes
we used to use to identify file types. Predicates that used to take strings
representing suffixes as arguments now have to specify whether they can
handle all these file types (source, interface and optimization),
or just (e.g.) all interface file types.
We used to have items corresponding to `:- module' and `:- end_module'.
Delete these; this information is now implicit in the structure of the
relevant AST. The parser handles the corresponding terms as markers,
not items; these markers are live only during parsing.
We used to have module_defns corresponding to `:- interface' and
`:- implementation'. Delete these; this information is now also implicit
in the structure of the relevant AST. Delete also, for the same reason,
the module_defns used to mark the starts of sublists in the overall lists
of items whose items came from the interface files or optimization files
of other modules. The former are now markers during parsing. The latter
are never parsed, but are created directly, after parsing has been done.
Delete the pragma type for `:- pragma source_file'. This is never
needed later; it is now a marker during parsing.
Change the internal representation of `:- import' and `:- use'.
It used to store a list of module names, but that list was an actual list
only during parsing; after that, it always had exactly one element.
It now stores one module name, and the parser has a mechanism to convert
one read-in term to more than one item, for use with terms such as
`:- import_module a, b'.
Delete the internal representation of `:- export', which was never
implemented, since if it IS ever implemented, it will almost certainly
be in a different form, which will need different support.
Document some further opportunities for simplification, later.
(This diff is already more than big enough.)
compiler/prog_io_item.m:
Rewrite the top-level part of this module. Instead of returning an item
for every parsed term, distinguish between parsing items that end up
in item lists inside ASTs, and parsing markers that end up creating
the STRUCTURE of those ASTs.
compiler/prog_io.m:
Rewrite the meat of this module. Instead of reading in a simple item list,
we now have to read in three different parse trees with three different
grammars, each of which is more complex than a simple list.
compiler/read_modules.m:
We used to have a map that mapped file names to the contents of those
files. We now need three separate maps, for interface files, optimization
files and source files, due to their separate types.
(We don't actually use the map for optimization files, which seems
to be a potential performance bug. The root cause of that problem
us that while intermod.m and the grab_*modules part of modules.m do
similar jobs, they don't use the same mechanisms.)
Replace the read_module predicate with the predicates read_module_src
and read_module_int, since these now return different types.
To avoid having to create AST-type-specialized variants of
read_module_ignore_errors and read_module_if_changed, give each of
read_module_{src,int} arguments that optionally tell them to ignore errors
and/or to read the module only if changed (though the "and" part of
"and/or" should not be needed.) These options already existed, but
they weren't exported.
compiler/timestamp.m:
Define the type we use for this option in read_modules.
compiler/status.m:
New module, containing mostly
- stuff carved out of hlds_pred.m, which defines the import_status type,
and the predicates that operate on it;
- stuff carved out of make_hlds_passes.m, which defines the item_status
type and the predicates that operate on that; and
- stuff carved out prog_data.m, which defines the section (now
module_section) and import_locn types.
It also contains the new section kinds we now use to represent item blocks
that were imported from interface and optimization files.
compiler/parse_tree.m:
compiler/notes/compiler_design.html:
Add status.m to the parse_tree package.
compiler/hlds_pred.m:
compiler/prog_data.m:
Remove the stuff now in status.m.
compiler/error_util.m:
Provide a mechanism to control the order of messages with respect to
ALL other messages, not just those that also specify ordering.
compiler/mercury_to_mercury.m:
Provide predicates for printing out parse_tree_* and *_compilation_unit,
since printing out a simple item list is no longer enough for debugging.
Pretty-print type definitions nicely.
Replace a boolean with a purpose-specific enum.
compiler/modules.m:
Rewrite virtually all this module to make it work on the new AST
representations. Generate more detailed error messages for duplicate
module inclusions. Note lots of possibilities for further improvements,
including in the documentation. Mark places I am still not sure about,
especially places where I am not sure *why* the code is doing
what it is doing.
compiler/module_imports.m:
This module stores the data structure in which we accumulate the stuff
imported into a compilation unit, i.e. it is in these data structures
that a raw_compilation_unit becomes an aug_compilation_unit. Modify
the data structure and the predicates that operate on it to work on the
new AST representations, not on an (apparently) simple list of items.
Avoid ambiguities by adding a prefix to field names.
Add some convenience predicates.
compiler/module_qual.m:
Perform module qualification on both raw lists of items (for use when
generating .int3 files) but also on item blocks (for use pretty much
in every other situation).
Generate warnings about module imports that are unnecessarily in the
module interface using the module's context (the context of the `:- module'
declaration), not line 1 of the relevant file.
compiler/prog_io_error.m:
Split some error categories more finely, since some error kinds here
actually used to be reported for more than one distinct situation.
compiler/prog_io_util.m:
Provide utility predicates that operate on nonempty lists.
compiler/recompilation.version.m:
Make the comparison of the old and new contents of the interface file
work on two parse_tree_ints, not on two raw sequences of items.
Delete a boolean option that was always `yes', never 'no'.
compiler/recompilation.m:
Turn some functions into predicates to allow the use of state variable
notation.
Avoid ambiguities by adding a prefix to field names.
compiler/write_module_interface_files.m:
Besides updating the code in this module to work on the new parse tree
representations, also use cords instead of reversed lists in several cases.
Note many possibilities for further improvements.
library/list.m:
Move the type one_or_more here from the compiler directory, since
we now use it in more than one compiler module, and this is its natural
home.
mdbcomp/sym_name.m:
Rename "match_sym_name" to "partial_sym_name_matches_full", since this
better describes its job.
Add a det version of sym_name_get_module_name.
compiler/equiv_type.m:
Rename some types to make them more expressive.
compiler/accumulator.m:
compiler/add_class.m:
compiler/add_foreign_enum.m:
compiler/add_foreign_proc.m:
compiler/add_mode.m:
compiler/add_pragma.m:
compiler/add_pragma_tabling.m:
compiler/add_pred.m:
compiler/add_solver.m:
compiler/add_special_pred.m:
compiler/add_type.m:
compiler/assertion.m:
compiler/base_typeclass_info.m:
compiler/check_typeclass.m:
compiler/ctgc.util.m:
compiler/dead_proc_elim.m:
compiler/dep_par_conj.m:
compiler/dependency_graph.m:
compiler/deps_map.m:
compiler/det_report.m:
compiler/elds_to_erlang.m:
compiler/equiv_type_hlds.m:
compiler/erl_code_gen.m:
compiler/export.m:
compiler/format_call.m:
compiler/higher_order.m:
compiler/hlds_data.m:
compiler/hlds_module.m:
compiler/hlds_out_pred.m:
compiler/inst_check.m:
compiler/intermod.m:
compiler/item_util.m:
compiler/lambda.m:
compiler/lco.m:
compiler/make.module_dep_file.m:
compiler/make_hlds.m:
compiler/make_hlds_error.m:
compiler/make_hlds_passes.m:
compiler/make_tags.m:
compiler/mercury_compile.m:
compiler/ml_proc_gen.m:
compiler/ml_type_gen.m:
compiler/mode_errors.m:
compiler/oisu_check.m:
compiler/par_loop_control.m:
compiler/polymorphism.m:
compiler/post_term_analysis.m:
compiler/post_typecheck.m:
compiler/pred_table.m:
compiler/prog_io_dcg.m:
compiler/prog_io_find.m:
compiler/prog_io_pragma.m:
compiler/prog_io_sym_name.m:
compiler/prog_io_type_defn.m:
compiler/prog_io_typeclass.m:
compiler/prop_mode_constraints.m:
compiler/push_goals_together.m:
compiler/qual_info.m:
compiler/recompilation.check.m:
compiler/recompilation.usage.m:
compiler/simplify_proc.m:
compiler/smm_common.m:
compiler/special_pred.m:
compiler/ssdebug.m:
compiler/stm_expand.m:
compiler/structure_reuse.analysis.m:
compiler/structure_reuse.direct.m:
compiler/structure_reuse.indirect.m:
compiler/structure_reuse.versions.m:
compiler/structure_sharing.analysis.m:
compiler/structure_sharing.domain.m:
compiler/table_gen.m:
compiler/term_constr_initial.m:
compiler/term_constr_main.m:
compiler/termination.m:
compiler/trace_params.m:
compiler/trans_opt.m:
compiler/type_class_info.m:
compiler/type_ctor_info.m:
compiler/typecheck.m:
compiler/typecheck_errors.m:
compiler/typecheck_info.m:
compiler/unify_proc.m:
compiler/untupling.m:
compiler/unused_args.m:
compiler/unused_imports.m:
compiler/write_deps_file.m:
compiler/xml_documentation.m:
Conform to the changes above.
tests/hard_coded/higher_order_func_test.m:
tests/hard_coded/higher_order_syntax.m:
Avoid a warning about importing a module in the interface, not the
implementation.
tests/invalid/after_end_module.err_exp:
tests/invalid/any_mode.err_exp:
tests/invalid/bad_end_module.err_exp:
tests/invalid/bigtest.err_exp:
tests/invalid/bug113.err_exp:
tests/invalid/duplicate_modes.err_exp:
tests/invalid/errors.err_exp:
tests/invalid/errors1.err_exp:
tests/invalid/errors2.err_exp:
tests/invalid/funcs_as_preds.err_exp:
tests/invalid/inst_list_dup.err_exp:
tests/invalid/invalid_main.err_exp:
tests/invalid/missing_interface_import2.err_exp:
tests/invalid/no_exports.err_exp:
tests/invalid/occurs.err_exp:
tests/invalid/predmode.err_exp:
tests/invalid/prog_io_erroneous.err_exp:
tests/invalid/type_inf_loop.err_exp:
tests/invalid/typeclass_missing_det_3.err_exp:
tests/invalid/typeclass_test_11.err_exp:
tests/invalid/types.err_exp:
tests/invalid/undef_inst.err_exp:
tests/invalid/undef_mode.err_exp:
tests/invalid/undef_type.err_exp:
tests/invalid/unicode1.err_exp:
tests/invalid/unicode2.err_exp:
tests/invalid/vars_in_wrong_places.err_exp:
tests/warnings/unused_import.exp:
tests/warnings/unused_interface_import.exp:
Update the expected outputs in the invalid and warnings directories
to account for one or more of the following five changes.
Error messages that warn about a module not exporting anything
used to always refer to line 1 of the module's source file.
Now expect these messages to refer to the actual context of the module,
which is the context of its `:- module' declaration.
Expect a similarly updated context for messages that warn about
unnecessarily importing modules in the interface, not in the
implementation.
Expect a similarly updated context for messages that warn about
importing a module via both `:- import_module' and `:- use_module'.
For the modules that follow the `:- module' declaration directly with code,
also expect an error message about the missing section marker.
For modules that have terms after the `:- end_module' declaration,
replace "end_module" with "`:- end_module'" in the error message.
tests/invalid/func_class.{m,err_exp}:
New test case. It is a copy of the old tests/valid/func_class.m, which
is missing more than one module marker. The expected output is what I think
we should generate. The test case currently fails, because we currently
print only a subset of the expected errors. I am pretty sure the reason
for that is that old code I have not modified simply throws away the
missing error messages. Fixing this is work for the near future.
tests/invalid/Mmakefile:
Enable the new test case.
tests/misc_tests/pretty_print_test.exp:
Expect the pretty-printed output to use four-space indentation,
per our current style guide, since the compiler now generates such output.
tests/misc_tests/pretty_print_test.m:
Clean up the source code of the test as well.
tests/valid/complicated_unify.m:
tests/valid/det_switch.m:
tests/valid/easy_nondet_test.m:
tests/valid/error.m:
tests/valid/func_class.m:
tests/valid/func_int_bug_main.m:
tests/valid/higher_order.m:
tests/valid/higher_order2.m:
tests/valid/implied_mode.m:
tests/valid/indexing.m:
tests/valid/multidet_test.m:
tests/valid/nasty_func_test.m:
tests/valid/semidet_disj.m:
tests/valid/stack_alloc.m:
tests/valid/switches.m:
Add missing section markers to these modules. They used to follow
the `:- module' declaration directly with code.
731 lines
28 KiB
Mathematica
731 lines
28 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1995-2012 The 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: dependency_graph.m.
|
|
% Main authors: bromage, conway, stayl.
|
|
%
|
|
% The dependency_graph records which procedures depend on which other
|
|
% procedures. It is defined as a digraph (see hlds_module.m) R where
|
|
% edge x -> y means that the definition of x depends on the definition of y.
|
|
% Note that imported procedures are not included in the dependency_graph
|
|
% (although opt_imported procedures are included).
|
|
%
|
|
% The other important structure is the dependency_ordering which is
|
|
% a list of the cliques (strongly-connected components) of this graph,
|
|
% in topological order. This is very handy for doing fixpoint iterations.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module transform_hlds.dependency_graph.
|
|
:- interface.
|
|
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module hlds.hlds_pred.
|
|
|
|
:- import_module io.
|
|
:- import_module list.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Ensure that the module_info contains a version of the dependency_info
|
|
% which only contains arcs between procedures for which there are clauses
|
|
% defined (everything that is not imported, plus opt_imported). There is
|
|
% no guarantee that the dependency_info is current.
|
|
%
|
|
:- pred module_info_ensure_dependency_info(module_info::in, module_info::out)
|
|
is det.
|
|
|
|
% Ensure that the module_info contains a version of the dependency_info
|
|
% which only contains arcs between procedures for which there are clauses
|
|
% defined (everything that is not imported, plus opt_imported). The
|
|
% dependency_info will be up-to-date.
|
|
%
|
|
:- pred module_info_rebuild_dependency_info(module_info::in, module_info::out,
|
|
dependency_info(pred_proc_id)::out) is det.
|
|
|
|
:- type include_imported
|
|
---> include_imported
|
|
; do_not_include_imported.
|
|
|
|
% Build the dependency graph of procedures.
|
|
%
|
|
:- pred build_pred_dependency_graph(module_info::in, list(pred_id)::in,
|
|
include_imported::in, dependency_info(pred_id)::out) is det.
|
|
|
|
% Build the dependency graph of predicates.
|
|
%
|
|
:- pred build_proc_dependency_graph(module_info::in, list(pred_id)::in,
|
|
include_imported::in, dependency_info(pred_proc_id)::out) is det.
|
|
|
|
% Output a form of the static call graph to a file, in a format suitable
|
|
% for use in .dependency_info files. After the heading, the format of
|
|
% each line is
|
|
%
|
|
% CallerModeDecl \t CalleeModeDecl
|
|
%
|
|
:- pred write_dependency_graph(module_info::in, module_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% Output a form of the static call graph to a file for use by the profiler.
|
|
% There is no heading, and the format of each line is
|
|
%
|
|
% CallerLabel \t CalleeLabel
|
|
%
|
|
:- pred write_prof_dependency_graph(module_info::in, module_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% Given the list of predicates in a strongly connected component
|
|
% of the dependency graph, a list of the higher SCCs in the module
|
|
% and a module_info, find out which members of the SCC can be
|
|
% called from outside the SCC.
|
|
%
|
|
:- pred get_scc_entry_points(list(pred_proc_id)::in, dependency_ordering::in,
|
|
module_info::in, list(pred_proc_id)::out) is det.
|
|
|
|
% write_graph(Graph, WriteNode, WriteEdge):
|
|
%
|
|
% Write out the dependency graph using WriteNode to decide what to output
|
|
% for a node in the dependency graph and WriteEdge for an edge.
|
|
%
|
|
:- pred write_graph(dependency_info::in,
|
|
pred(pred_proc_id, io, io)::pred(in, di, uo) is det,
|
|
pred(pred_proc_id, pred_proc_id, io, io)::pred(in, in, di, uo) is det,
|
|
io::di, io::uo) is det.
|
|
|
|
% write_graph_nodes(Nodes, Graph, WriteNode, WriteEdge)
|
|
%
|
|
% Write out each of the Nodes in the Graph using WriteNode and
|
|
% any edges originating in Nodes, using WriteEdge.
|
|
%
|
|
:- pred write_graph_nodes(list(pred_proc_id)::in, dependency_graph::in,
|
|
pred(pred_proc_id, io, io)::pred(in, di, uo) is det,
|
|
pred(pred_proc_id, pred_proc_id, io, io)::pred(in, in, di, uo) is det,
|
|
io::di, io::uo) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module backend_libs.
|
|
:- import_module backend_libs.name_mangle.
|
|
:- import_module backend_libs.proc_label.
|
|
:- import_module hlds.hlds_clauses.
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.mercury_to_mercury.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.status.
|
|
|
|
:- import_module bool.
|
|
:- import_module digraph.
|
|
:- import_module int.
|
|
:- import_module map.
|
|
:- import_module maybe.
|
|
:- import_module multi_map.
|
|
:- import_module pair.
|
|
:- import_module set.
|
|
:- import_module std_util.
|
|
:- import_module term.
|
|
:- import_module varset.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
module_info_ensure_dependency_info(!ModuleInfo) :-
|
|
module_info_get_maybe_dependency_info(!.ModuleInfo, MaybeDepInfo),
|
|
(
|
|
MaybeDepInfo = yes(_)
|
|
;
|
|
MaybeDepInfo = no,
|
|
module_info_get_valid_pred_ids(!.ModuleInfo, PredIds),
|
|
build_dependency_graph(!.ModuleInfo, PredIds, do_not_include_imported,
|
|
DepInfo),
|
|
module_info_set_dependency_info(DepInfo, !ModuleInfo)
|
|
).
|
|
|
|
module_info_rebuild_dependency_info(!ModuleInfo, DepInfo) :-
|
|
module_info_get_valid_pred_ids(!.ModuleInfo, PredIds),
|
|
build_dependency_graph(!.ModuleInfo, PredIds, do_not_include_imported,
|
|
DepInfo),
|
|
module_info_set_dependency_info(DepInfo, !ModuleInfo).
|
|
|
|
build_proc_dependency_graph(ModuleInfo, PredIds, Imported, DepInfo) :-
|
|
build_dependency_graph(ModuleInfo, PredIds, Imported, DepInfo).
|
|
|
|
build_pred_dependency_graph(ModuleInfo, PredIds, Imported, DepInfo) :-
|
|
build_dependency_graph(ModuleInfo, PredIds, Imported, DepInfo).
|
|
|
|
% Traverse the module structure, calling `add_dependency_arcs'
|
|
% for each procedure body.
|
|
%
|
|
:- pred build_dependency_graph(module_info::in, list(pred_id)::in,
|
|
include_imported::in, dependency_info(T)::out) is det
|
|
<= dependency_node(T).
|
|
|
|
build_dependency_graph(ModuleInfo, PredIds, Imported, !:DepInfo) :-
|
|
digraph.init(DepGraph0),
|
|
add_dependency_nodes(PredIds, ModuleInfo, Imported, DepGraph0, DepGraph1),
|
|
add_dependency_arcs(PredIds, ModuleInfo, Imported, DepGraph1, DepGraph),
|
|
hlds_dependency_info_init(!:DepInfo),
|
|
hlds_dependency_info_set_dependency_graph(DepGraph, !DepInfo),
|
|
digraph.atsort(DepGraph, DepOrd0),
|
|
sets_to_lists(DepOrd0, [], DepOrd),
|
|
hlds_dependency_info_set_dependency_ordering(DepOrd, !DepInfo).
|
|
|
|
:- pred sets_to_lists(list(set(T))::in, list(list(T))::in,
|
|
list(list(T))::out) is det.
|
|
|
|
sets_to_lists([], Xs, Xs).
|
|
sets_to_lists([X | Xs], Ys, Zs) :-
|
|
set.to_sorted_list(X, Y),
|
|
sets_to_lists(Xs, [Y | Ys], Zs).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- typeclass dependency_node(T) where [
|
|
pred add_dependency_nodes(list(pred_id)::in, module_info::in,
|
|
include_imported::in,
|
|
dependency_graph(T)::in, dependency_graph(T)::out) is det,
|
|
|
|
pred add_dependency_arcs(list(pred_id)::in, module_info::in,
|
|
include_imported::in,
|
|
dependency_graph(T)::in, dependency_graph(T)::out) is det,
|
|
|
|
func dependency_node(pred_proc_id) = T
|
|
].
|
|
|
|
:- instance dependency_node(pred_proc_id) where [
|
|
pred(add_dependency_nodes/5) is add_pred_proc_nodes,
|
|
pred(add_dependency_arcs/5) is add_pred_proc_arcs,
|
|
func(dependency_node/1) is id
|
|
].
|
|
|
|
:- instance dependency_node(pred_id) where [
|
|
pred(add_dependency_nodes/5) is add_pred_nodes,
|
|
pred(add_dependency_arcs/5) is add_pred_arcs,
|
|
func(dependency_node/1) is pred_proc_id_get_pred_id
|
|
].
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred add_pred_proc_nodes(list(pred_id)::in, module_info::in,
|
|
include_imported::in, dependency_graph::in, dependency_graph::out) is det.
|
|
|
|
add_pred_proc_nodes([], _ModuleInfo, _, !DepGraph).
|
|
add_pred_proc_nodes([PredId | PredIds], ModuleInfo, Imported, !DepGraph) :-
|
|
module_info_get_preds(ModuleInfo, PredTable),
|
|
map.lookup(PredTable, PredId, PredInfo),
|
|
(
|
|
% Don't bother adding nodes (or arcs) for procedures which are imported
|
|
% (i.e. which we don't have any `clauses' for).
|
|
Imported = do_not_include_imported,
|
|
ProcIds = pred_info_non_imported_procids(PredInfo)
|
|
;
|
|
Imported = include_imported,
|
|
ProcIds = pred_info_procids(PredInfo)
|
|
),
|
|
add_proc_nodes(ProcIds, PredId, ModuleInfo, !DepGraph),
|
|
add_pred_proc_nodes(PredIds, ModuleInfo, Imported, !DepGraph).
|
|
|
|
:- pred add_proc_nodes(list(proc_id)::in, pred_id::in,
|
|
module_info::in, dependency_graph::in, dependency_graph::out) is det.
|
|
|
|
add_proc_nodes([], _PredId, _ModuleInfo, !DepGraph).
|
|
add_proc_nodes([ProcId | ProcIds], PredId, ModuleInfo, !DepGraph) :-
|
|
digraph.add_vertex(proc(PredId, ProcId), _, !DepGraph),
|
|
add_proc_nodes(ProcIds, PredId, ModuleInfo, !DepGraph).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred add_pred_nodes(list(pred_id)::in, module_info::in,
|
|
include_imported::in,
|
|
dependency_graph(pred_id)::in, dependency_graph(pred_id)::out) is det.
|
|
|
|
add_pred_nodes([], _ModuleInfo, _, DepGraph, DepGraph).
|
|
add_pred_nodes([PredId | PredIds], ModuleInfo, IncludeImported, !DepGraph) :-
|
|
module_info_get_preds(ModuleInfo, PredTable),
|
|
map.lookup(PredTable, PredId, PredInfo),
|
|
% Don't bother adding nodes (or arcs) for predicates
|
|
% which are imported (i.e. which we don't have any `clauses' for).
|
|
(
|
|
IncludeImported = do_not_include_imported,
|
|
pred_info_is_imported(PredInfo)
|
|
->
|
|
true
|
|
;
|
|
digraph.add_vertex(PredId, _, !DepGraph)
|
|
),
|
|
add_pred_nodes(PredIds, ModuleInfo, IncludeImported, !DepGraph).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred add_pred_proc_arcs(list(pred_id)::in, module_info::in,
|
|
include_imported::in, dependency_graph::in, dependency_graph::out) is det.
|
|
|
|
add_pred_proc_arcs([], _ModuleInfo, _, !DepGraph).
|
|
add_pred_proc_arcs([PredId | PredIds], ModuleInfo, Imported, !DepGraph) :-
|
|
module_info_get_preds(ModuleInfo, PredTable),
|
|
map.lookup(PredTable, PredId, PredInfo),
|
|
(
|
|
% Don't bother adding nodes (or arcs) for procedures which are imported
|
|
% (i.e. which we don't have any `clauses' for).
|
|
Imported = do_not_include_imported,
|
|
ProcIds = pred_info_non_imported_procids(PredInfo)
|
|
;
|
|
Imported = include_imported,
|
|
ProcIds = pred_info_procids(PredInfo)
|
|
),
|
|
add_proc_arcs(ProcIds, PredId, ModuleInfo, Imported, !DepGraph),
|
|
add_pred_proc_arcs(PredIds, ModuleInfo, Imported, !DepGraph).
|
|
|
|
:- pred add_proc_arcs(list(proc_id)::in, pred_id::in, module_info::in,
|
|
include_imported::in, dependency_graph::in, dependency_graph::out) is det.
|
|
|
|
add_proc_arcs([], _PredId, _ModuleInfo, _, !DepGraph).
|
|
add_proc_arcs([ProcId | ProcIds], PredId, ModuleInfo, IncludeImported,
|
|
!DepGraph) :-
|
|
module_info_get_preds(ModuleInfo, PredTable0),
|
|
map.lookup(PredTable0, PredId, PredInfo0),
|
|
pred_info_get_proc_table(PredInfo0, ProcTable0),
|
|
map.lookup(ProcTable0, ProcId, ProcInfo0),
|
|
(
|
|
IncludeImported = do_not_include_imported,
|
|
proc_info_get_goal(ProcInfo0, Goal),
|
|
|
|
digraph.lookup_key(!.DepGraph, proc(PredId, ProcId), Caller),
|
|
add_dependency_arcs_in_goal(Caller, Goal, !DepGraph)
|
|
;
|
|
IncludeImported = include_imported,
|
|
pred_info_get_import_status(PredInfo0, ImportStatus),
|
|
Imported = status_is_imported(ImportStatus),
|
|
(
|
|
Imported = yes
|
|
;
|
|
Imported = no,
|
|
proc_info_get_goal(ProcInfo0, Goal),
|
|
digraph.lookup_key(!.DepGraph, proc(PredId, ProcId), Caller),
|
|
add_dependency_arcs_in_goal(Caller, Goal, !DepGraph)
|
|
)
|
|
),
|
|
add_proc_arcs(ProcIds, PredId, ModuleInfo, IncludeImported, !DepGraph).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred add_pred_arcs(list(pred_id)::in, module_info::in, include_imported::in,
|
|
dependency_graph(pred_id)::in, dependency_graph(pred_id)::out) is det.
|
|
|
|
add_pred_arcs([], _ModuleInfo, _, !DepGraph).
|
|
add_pred_arcs([PredId | PredIds], ModuleInfo, IncludeImported, !DepGraph) :-
|
|
module_info_get_preds(ModuleInfo, PredTable),
|
|
map.lookup(PredTable, PredId, PredInfo),
|
|
(
|
|
IncludeImported = do_not_include_imported,
|
|
pred_info_is_imported(PredInfo)
|
|
->
|
|
true
|
|
;
|
|
pred_info_get_clauses_info(PredInfo, ClausesInfo),
|
|
clauses_info_get_clauses_rep(ClausesInfo, ClausesRep, _ItemNumbers),
|
|
get_clause_list_any_order(ClausesRep, Clauses),
|
|
Goals = list.map(clause_body, Clauses),
|
|
digraph.lookup_key(!.DepGraph, PredId, Caller),
|
|
add_dependency_arcs_in_goals(Caller, Goals, !DepGraph)
|
|
),
|
|
add_pred_arcs(PredIds, ModuleInfo, IncludeImported, !DepGraph).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- func pred_proc_id_get_pred_id(pred_proc_id) = pred_id.
|
|
|
|
pred_proc_id_get_pred_id(proc(PredId, _)) = PredId.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred add_dependency_arcs_in_goal(digraph_key(T)::in, hlds_goal::in,
|
|
dependency_graph(T)::in, dependency_graph(T)::out) is det
|
|
<= dependency_node(T).
|
|
|
|
add_dependency_arcs_in_goal(Caller, Goal, !DepGraph) :-
|
|
Goal = hlds_goal(GoalExpr, _),
|
|
(
|
|
( GoalExpr = conj(_, Goals)
|
|
; GoalExpr = disj(Goals)
|
|
),
|
|
add_dependency_arcs_in_goals(Caller, Goals, !DepGraph)
|
|
;
|
|
GoalExpr = switch(_Var, _Det, Cases),
|
|
add_dependency_arcs_in_cases(Caller, Cases, !DepGraph)
|
|
;
|
|
GoalExpr = if_then_else(_Vars, Cond, Then, Else),
|
|
add_dependency_arcs_in_goal(Caller, Cond, !DepGraph),
|
|
add_dependency_arcs_in_goal(Caller, Then, !DepGraph),
|
|
add_dependency_arcs_in_goal(Caller, Else, !DepGraph)
|
|
;
|
|
GoalExpr = negation(SubGoal),
|
|
add_dependency_arcs_in_goal(Caller, SubGoal, !DepGraph)
|
|
;
|
|
GoalExpr = scope(Reason, SubGoal),
|
|
(
|
|
Reason = from_ground_term(_, FGT),
|
|
( FGT = from_ground_term_construct
|
|
; FGT = from_ground_term_deconstruct
|
|
)
|
|
->
|
|
% The scope references no predicates or procedures.
|
|
true
|
|
;
|
|
add_dependency_arcs_in_goal(Caller, SubGoal, !DepGraph)
|
|
)
|
|
;
|
|
GoalExpr = generic_call(_, _, _, _, _)
|
|
;
|
|
GoalExpr = plain_call(PredId, ProcId, _, Builtin, _, _),
|
|
(
|
|
Builtin = inline_builtin
|
|
;
|
|
( Builtin = out_of_line_builtin
|
|
; Builtin = not_builtin
|
|
),
|
|
(
|
|
% If the node isn't in the graph, then we didn't insert it
|
|
% because is was imported, and we don't consider it.
|
|
digraph.search_key(!.DepGraph,
|
|
dependency_node(proc(PredId, ProcId)), Callee)
|
|
->
|
|
digraph.add_edge(Caller, Callee, !DepGraph)
|
|
;
|
|
true
|
|
)
|
|
)
|
|
;
|
|
GoalExpr = unify(_,_,_,Unify,_),
|
|
(
|
|
Unify = assign(_, _)
|
|
;
|
|
Unify = simple_test(_, _)
|
|
;
|
|
Unify = construct(_, ConsId, _, _, _, _, _),
|
|
add_dependency_arcs_in_cons(Caller, ConsId, !DepGraph)
|
|
;
|
|
Unify = deconstruct(_, ConsId, _, _, _, _),
|
|
add_dependency_arcs_in_cons(Caller, ConsId, !DepGraph)
|
|
;
|
|
Unify = complicated_unify(_, _, _)
|
|
)
|
|
;
|
|
GoalExpr = call_foreign_proc(_, _, _, _, _, _, _)
|
|
;
|
|
GoalExpr = shorthand(ShortHand),
|
|
(
|
|
ShortHand = atomic_goal(_GoalType, _Outer, _Inner, _Vars,
|
|
MainGoal, OrElseGoals, _OrElseInners),
|
|
add_dependency_arcs_in_goal(Caller, MainGoal, !DepGraph),
|
|
add_dependency_arcs_in_goals(Caller, OrElseGoals, !DepGraph)
|
|
;
|
|
ShortHand = try_goal(_, _, SubGoal),
|
|
add_dependency_arcs_in_goal(Caller, SubGoal, !DepGraph)
|
|
;
|
|
ShortHand = bi_implication(LHS, RHS),
|
|
add_dependency_arcs_in_goal(Caller, LHS, !DepGraph),
|
|
add_dependency_arcs_in_goal(Caller, RHS, !DepGraph)
|
|
)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred add_dependency_arcs_in_goals(digraph_key(T)::in, list(hlds_goal)::in,
|
|
dependency_graph(T)::in, dependency_graph(T)::out) is det
|
|
<= dependency_node(T).
|
|
|
|
add_dependency_arcs_in_goals(_Caller, [], !DepGraph).
|
|
add_dependency_arcs_in_goals(Caller, [Goal | Goals], !DepGraph) :-
|
|
add_dependency_arcs_in_goal(Caller, Goal, !DepGraph),
|
|
add_dependency_arcs_in_goals(Caller, Goals, !DepGraph).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred add_dependency_arcs_in_cases(digraph_key(T)::in, list(case)::in,
|
|
dependency_graph(T)::in, dependency_graph(T)::out) is det
|
|
<= dependency_node(T).
|
|
|
|
add_dependency_arcs_in_cases(_Caller, [], !DepGraph).
|
|
add_dependency_arcs_in_cases(Caller, [Case | Cases], !DepGraph) :-
|
|
Case = case(MainConsId, OtherConsIds, Goal),
|
|
add_dependency_arcs_in_cons(Caller, MainConsId, !DepGraph),
|
|
list.foldl(add_dependency_arcs_in_cons(Caller), OtherConsIds, !DepGraph),
|
|
add_dependency_arcs_in_goal(Caller, Goal, !DepGraph),
|
|
add_dependency_arcs_in_cases(Caller, Cases, !DepGraph).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred add_dependency_arcs_in_cons(digraph_key(T)::in, cons_id::in,
|
|
dependency_graph(T)::in, dependency_graph(T)::out) is det
|
|
<= dependency_node(T).
|
|
|
|
add_dependency_arcs_in_cons(Caller, ConsId, !DepGraph) :-
|
|
(
|
|
ConsId = closure_cons(ShroudedPredProcId, _),
|
|
PredProcId = unshroud_pred_proc_id(ShroudedPredProcId),
|
|
(
|
|
% If the node isn't in the graph, then we didn't insert it
|
|
% because it was imported, and we don't consider it.
|
|
digraph.search_key(!.DepGraph, dependency_node(PredProcId), Callee)
|
|
->
|
|
digraph.add_edge(Caller, Callee, !DepGraph)
|
|
;
|
|
true
|
|
)
|
|
;
|
|
( ConsId = cons(_, _, _)
|
|
; ConsId = tuple_cons(_)
|
|
; ConsId = int_const(_)
|
|
; ConsId = float_const(_)
|
|
; ConsId = char_const(_)
|
|
; ConsId = string_const(_)
|
|
; ConsId = impl_defined_const(_)
|
|
; ConsId = type_ctor_info_const(_, _, _)
|
|
; ConsId = base_typeclass_info_const(_, _, _, _)
|
|
; ConsId = type_info_cell_constructor(_)
|
|
; ConsId = typeclass_info_cell_constructor
|
|
; ConsId = type_info_const(_)
|
|
; ConsId = typeclass_info_const(_)
|
|
; ConsId = ground_term_const(_, _)
|
|
; ConsId = tabling_info_const(_)
|
|
; ConsId = table_io_entry_desc(_)
|
|
; ConsId = deep_profiling_proc_layout(_)
|
|
)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred write_dependency_ordering( list(list(pred_proc_id))::in,
|
|
module_info::in, int::in, io::di, io::uo) is det.
|
|
|
|
write_dependency_ordering([], _ModuleInfo, _N, !IO) :-
|
|
io.write_string("\n", !IO).
|
|
write_dependency_ordering([Clique | Rest], ModuleInfo, N, !IO) :-
|
|
io.write_string("% Clique ", !IO),
|
|
io.write_int(N, !IO),
|
|
io.write_string("\n", !IO),
|
|
write_clique(Clique, ModuleInfo, !IO),
|
|
N1 = N + 1,
|
|
write_dependency_ordering(Rest, ModuleInfo, N1, !IO).
|
|
|
|
:- pred write_clique(list(pred_proc_id)::in, module_info::in, io::di, io::uo)
|
|
is det.
|
|
|
|
write_clique([], _ModuleInfo, !IO).
|
|
write_clique([proc(PredId, ProcId) | Rest], ModuleInfo, !IO) :-
|
|
module_info_pred_proc_info(ModuleInfo, PredId, ProcId, PredInfo, ProcInfo),
|
|
Name = pred_info_name(PredInfo),
|
|
proc_info_get_declared_determinism(ProcInfo, Det),
|
|
proc_info_get_argmodes(ProcInfo, Modes),
|
|
proc_info_get_context(ProcInfo, Context),
|
|
varset.init(ModeVarSet),
|
|
|
|
io.write_string("% ", !IO),
|
|
mercury_output_pred_mode_subdecl(output_mercury,ModeVarSet,
|
|
unqualified(Name), Modes, Det, Context, !IO),
|
|
io.write_string("\n", !IO),
|
|
write_clique(Rest, ModuleInfo, !IO).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
write_prof_dependency_graph(!ModuleInfo, !IO) :-
|
|
module_info_ensure_dependency_info(!ModuleInfo),
|
|
module_info_dependency_info(!.ModuleInfo, DepInfo),
|
|
write_graph(DepInfo, write_empty_node,
|
|
write_prof_dep_graph_link(!.ModuleInfo), !IO).
|
|
|
|
write_dependency_graph(!ModuleInfo, !IO) :-
|
|
module_info_ensure_dependency_info(!ModuleInfo),
|
|
module_info_dependency_info(!.ModuleInfo, DepInfo),
|
|
io.write_string("% Dependency graph\n", !IO),
|
|
io.write_string("\n\n% Dependency ordering\n", !IO),
|
|
write_graph(DepInfo, write_empty_node,
|
|
write_dep_graph_link(!.ModuleInfo), !IO).
|
|
|
|
:- pred write_empty_node(pred_proc_id::in, io::di, io::uo) is det.
|
|
|
|
write_empty_node(_, !IO).
|
|
|
|
:- pred write_prof_dep_graph_link(module_info::in,
|
|
pred_proc_id::in, pred_proc_id::in, io::di, io::uo) is det.
|
|
|
|
write_prof_dep_graph_link(ModuleInfo, Parent, Child, !IO) :-
|
|
Parent = proc(PPredId, PProcId), % Caller
|
|
Child = proc(CPredId, CProcId), % Callee
|
|
output_label_dependency(ModuleInfo, PPredId, PProcId, !IO),
|
|
io.write_string("\t", !IO),
|
|
output_label_dependency(ModuleInfo, CPredId, CProcId, !IO),
|
|
io.write_string("\n", !IO).
|
|
|
|
:- pred write_dep_graph_link(module_info::in,
|
|
pred_proc_id::in, pred_proc_id::in, io::di, io::uo) is det.
|
|
|
|
write_dep_graph_link(ModuleInfo, Parent, Child, !IO) :-
|
|
Parent = proc(PPredId, PProcId), % Caller
|
|
Child = proc(CPredId, CProcId), % Callee
|
|
module_info_pred_proc_info(ModuleInfo, PPredId, PProcId,
|
|
PPredInfo, PProcInfo),
|
|
module_info_pred_proc_info(ModuleInfo, CPredId, CProcId,
|
|
CPredInfo, CProcInfo),
|
|
PName = pred_info_name(PPredInfo),
|
|
proc_info_get_declared_determinism(PProcInfo, PDet),
|
|
proc_info_get_argmodes(PProcInfo, PModes),
|
|
proc_info_get_context(PProcInfo, PContext),
|
|
CName = pred_info_name(CPredInfo),
|
|
proc_info_get_declared_determinism(CProcInfo, CDet),
|
|
proc_info_get_argmodes(CProcInfo, CModes),
|
|
proc_info_get_context(CProcInfo, CContext),
|
|
varset.init(ModeVarSet),
|
|
mercury_output_pred_mode_subdecl(output_mercury, ModeVarSet,
|
|
unqualified(PName), PModes, PDet, PContext, !IO),
|
|
io.write_string(" -> ", !IO),
|
|
mercury_output_pred_mode_subdecl(output_mercury, ModeVarSet,
|
|
unqualified(CName), CModes, CDet, CContext, !IO),
|
|
io.write_string("\n", !IO).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
write_graph(DepInfo, WriteNode, WriteLink, !IO) :-
|
|
hlds_dependency_info_get_dependency_graph(DepInfo, DepGraph),
|
|
digraph.vertices(DepGraph, DomSet),
|
|
set.to_sorted_list(DomSet, DomList),
|
|
write_graph_nodes(DomList, DepGraph, WriteNode, WriteLink, !IO).
|
|
|
|
write_graph_nodes([], _Graph, _WriteNode, _WriteLink, !IO).
|
|
write_graph_nodes([Node | Nodes], Graph, WriteNode, WriteLink, !IO) :-
|
|
WriteNode(Node, !IO),
|
|
digraph.lookup_key(Graph, Node, NodeKey),
|
|
digraph.lookup_from(Graph, NodeKey, ChildrenSet),
|
|
set.to_sorted_list(ChildrenSet, Children),
|
|
write_graph_children(Children, Node, Graph, WriteLink, !IO),
|
|
write_graph_nodes(Nodes, Graph, WriteNode, WriteLink, !IO).
|
|
|
|
:- pred write_graph_children(list(dependency_graph_key)::in, pred_proc_id::in,
|
|
dependency_graph::in,
|
|
pred(pred_proc_id, pred_proc_id, io, io)::pred(in, in, di, uo) is det,
|
|
io::di, io::uo) is det.
|
|
|
|
write_graph_children([], _Parent, _Graph, _WriteLink, !IO).
|
|
write_graph_children([ChildKey | Children], Parent, Graph, WriteLink, !IO) :-
|
|
digraph.lookup_vertex(Graph, ChildKey, Child),
|
|
WriteLink(Parent, Child, !IO),
|
|
write_graph_children(Children, Parent, Graph, WriteLink, !IO).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Print out the label corresponding to the given pred_id and proc_id.
|
|
%
|
|
:- pred output_label_dependency(module_info::in, pred_id::in, proc_id::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_label_dependency(ModuleInfo, PredId, ProcId, !IO) :-
|
|
ProcLabel = make_proc_label(ModuleInfo, PredId, ProcId),
|
|
output_proc_label(ProcLabel, !IO).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
get_scc_entry_points(SCC, HigherSCCs, ModuleInfo, EntryPoints) :-
|
|
list.filter(is_entry_point(HigherSCCs, ModuleInfo), SCC, EntryPoints).
|
|
|
|
:- pred is_entry_point(list(list(pred_proc_id))::in, module_info::in,
|
|
pred_proc_id::in) is semidet.
|
|
|
|
is_entry_point(HigherSCCs, ModuleInfo, PredProcId) :-
|
|
(
|
|
% Is the predicate exported?
|
|
PredProcId = proc(PredId, _ProcId),
|
|
module_info_pred_info(ModuleInfo, PredId, PredInfo),
|
|
pred_info_is_exported(PredInfo)
|
|
;
|
|
% Is the predicate called from a higher SCC?
|
|
module_info_dependency_info(ModuleInfo, DepInfo),
|
|
hlds_dependency_info_get_dependency_graph(DepInfo, DepGraph),
|
|
|
|
digraph.lookup_key(DepGraph, PredProcId, PredProcIdKey),
|
|
digraph.lookup_to(DepGraph, PredProcIdKey, CallingKeys),
|
|
set.member(CallingKey, CallingKeys),
|
|
digraph.lookup_vertex(DepGraph, CallingKey, CallingPred),
|
|
list.member(HigherSCC, HigherSCCs),
|
|
list.member(CallingPred, HigherSCC)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Find the SCCs called from a given SCC.
|
|
%
|
|
:- pred get_called_scc_ids(scc_id::in, digraph(scc_id)::in, set(scc_id)::out)
|
|
is det.
|
|
|
|
get_called_scc_ids(SCCid, SCCRel, CalledSCCSet) :-
|
|
digraph.lookup_key(SCCRel, SCCid, SCCidKey),
|
|
digraph.lookup_from(SCCRel, SCCidKey, CalledSCCKeys),
|
|
set.to_sorted_list(CalledSCCKeys, CalledSCCKeyList),
|
|
list.map(digraph.lookup_vertex(SCCRel), CalledSCCKeyList, CalledSCCs),
|
|
set.list_to_set(CalledSCCs, CalledSCCSet).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type scc_id == int.
|
|
|
|
% An SCC cannot be merged into its parents if one of its procedures
|
|
% is called as an aggregate query.
|
|
%
|
|
:- pred handle_higher_order_args(list(prog_var)::in, bool::in, scc_id::in,
|
|
multi_map(prog_var, pred_proc_id)::in, map(pred_proc_id, scc_id)::in,
|
|
digraph(scc_id)::in, digraph(scc_id)::out,
|
|
set(scc_id)::in, set(scc_id)::out) is det.
|
|
|
|
handle_higher_order_args([], _, _, _, _, !SCCRel, !NoMerge).
|
|
handle_higher_order_args([Arg | Args], IsAgg, SCCid, Map, PredSCC,
|
|
!SCCGraph, !NoMerge) :-
|
|
( multi_map.search(Map, Arg, PredProcIds) ->
|
|
list.foldl2(handle_higher_order_arg(PredSCC, IsAgg, SCCid),
|
|
PredProcIds, !SCCGraph, !NoMerge)
|
|
;
|
|
true
|
|
),
|
|
handle_higher_order_args(Args, IsAgg, SCCid, Map, PredSCC,
|
|
!SCCGraph, !NoMerge).
|
|
|
|
:- pred handle_higher_order_arg(map(pred_proc_id, scc_id)::in, bool::in,
|
|
scc_id::in, pred_proc_id::in,
|
|
digraph(scc_id)::in, digraph(scc_id)::out,
|
|
set(scc_id)::in, set(scc_id)::out) is det.
|
|
|
|
handle_higher_order_arg(PredSCC, IsAgg, SCCid, PredProcId,
|
|
!SCCGraph, !NoMerge) :-
|
|
( map.search(PredSCC, PredProcId, CalledSCCid) ->
|
|
% Make sure anything called through an aggregate
|
|
% is not merged into the current sub-module.
|
|
(
|
|
IsAgg = yes,
|
|
set.insert(CalledSCCid, !NoMerge)
|
|
;
|
|
IsAgg = no
|
|
),
|
|
( CalledSCCid = SCCid ->
|
|
true
|
|
;
|
|
digraph.add_vertices_and_edge(SCCid, CalledSCCid, !SCCGraph)
|
|
)
|
|
;
|
|
true
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- end_module transform_hlds.dependency_graph.
|
|
%-----------------------------------------------------------------------------%
|