[m-rev.] for preliminary review: Add option to break trans-opt dependencies.

Peter Wang novalazy at gmail.com
Mon Dec 19 17:48:18 AEDT 2022


Hi,

Here is a patch to improve parallel making of .trans_opt files.
The naming of things is rather clunky.

Here are times for "mmake -j32 trans_opts" in the library directory,
using the attached mer_std.make-trans-opt-deps file:

- without the new option

    real        0m39.742s
    user        2m11.086s
    sys         0m5.166s

- with --make-trans-opt-deps-spec

    real        0m18.700s
    user        1m42.337s
    sys         0m4.331s

It should be possible to improve it by deleting more (unnecessary)
dependencies on .trans_opt files.

A diff showing the changes to the .trans_opt files is attached.
The analysis results are mostly improved, with only a few regressions.

The information of interest in the mer_std.make-trans-opt-deps file is
all in the %-commented out lines. For a given source module, we want to
prevent the compiler reading another module's .trans_opt file.
Therefore, I'm thinking the file should state the negative dependencies
directly, e.g.

    foo - {
        not bar,
        not baz
    }

This is of course similar to my pragma no_trans_opt proposal,
only contained in a single file (arguably better).

Peter
-------------- next part --------------
diff --git a/compiler/generate_dep_d_files.m b/compiler/generate_dep_d_files.m
index 4c7277722..1467db53f 100644
--- a/compiler/generate_dep_d_files.m
+++ b/compiler/generate_dep_d_files.m
@@ -76,6 +76,7 @@
 :- import_module parse_tree.module_dep_info.
 :- import_module parse_tree.module_deps_graph.
 :- import_module parse_tree.parse_error.
+:- import_module parse_tree.parse_sym_name.
 :- import_module parse_tree.prog_item.
 :- import_module parse_tree.read_modules.
 :- import_module parse_tree.write_deps_file.
@@ -83,12 +84,16 @@
 
 :- import_module bool.
 :- import_module digraph.
+:- import_module int.
 :- import_module list.
 :- import_module map.
 :- import_module maybe.
+:- import_module mercury_term_parser.
 :- import_module pair.
 :- import_module set.
 :- import_module string.
+:- import_module term.
+:- import_module term_context.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -191,7 +196,6 @@ generate_dependencies(Globals, Mode, Search, ModuleName, DepsMap0, !IO) :-
 
         % Compute the interface deps graph and the implementation deps
         % graph from the deps map.
-
         digraph.init(IntDepsGraph0),
         digraph.init(ImpDepsGraph0),
         map.values(DepsMap, DepsList),
@@ -200,19 +204,10 @@ generate_dependencies(Globals, Mode, Search, ModuleName, DepsMap0, !IO) :-
         maybe_output_imports_graph(Globals, ModuleName,
             IntDepsGraph, ImpDepsGraph, !IO),
 
-        % Compute the trans-opt deps ordering, by doing an approximate
-        % topological sort of the implementation deps, and then finding
-        % the subset of those for which of those we have (or can make)
-        % trans-opt files.
-
-        digraph.atsort(ImpDepsGraph, ImpDepsOrdering0),
-        maybe_output_module_order(Globals, ModuleName, ImpDepsOrdering0, !IO),
-        list.map(set.to_sorted_list, ImpDepsOrdering0, ImpDepsOrdering),
-        list.condense(ImpDepsOrdering, TransOptDepsOrdering0),
-        globals.lookup_accumulating_option(Globals, intermod_directories,
-            IntermodDirs),
-        get_opt_deps(Globals, yes, IntermodDirs, other_ext(".trans_opt"),
-            TransOptDepsOrdering0, TransOptDepsOrdering, !IO),
+        % XXX create ImpDepsOrdering only if we will write a .order file
+        digraph.atsort(ImpDepsGraph, ImpDepsOrdering),
+        maybe_output_module_order(Globals, ModuleName, other_ext(".order"),
+            ImpDepsOrdering, !IO),
 
         trace [compiletime(flag("deps_graph")), runtime(env("DEPS_GRAPH")),
             io(!TIO)]
@@ -228,7 +223,6 @@ generate_dependencies(Globals, Mode, Search, ModuleName, DepsMap0, !IO) :-
         % implementation dependencies. (We used to take the transitive closure
         % of the interface dependencies, but we now include implementation
         % details in the interface files).
-
         digraph.tc(ImpDepsGraph, TransImpDepsGraph),
         digraph.compose(ImpDepsGraph, TransImpDepsGraph, IndirectDepsGraph),
 
@@ -240,9 +234,61 @@ generate_dependencies(Globals, Mode, Search, ModuleName, DepsMap0, !IO) :-
         % and assume that the each module's `.opt' file might import any
         % of that module's implementation dependencies; in actual fact,
         % it will be some subset of that.
-
         digraph.tc(ImpDepsGraph, IndirectOptDepsGraph),
 
+        % Compute the trans-opt deps for the purposes of making trans-opt
+        % files. This is normally equal to transitive closure of the indirect
+        % dependencies (i.e. IndirectOptDepsGraph) since a module may read the
+        % `.trans_opt' file of any directly or indirectly imported module.
+        %
+        % To deal with cycles in the graph, we impose an arbitrary order on
+        % modules so that, when making the trans-opt file for a module
+        % "earlier" in the cycle, the compiler may read the trans-opt files
+        % of modules "later" in the cycle, but not vice versa.
+        %
+        % The problem with that is twofold:
+        % - Lack of parallelism. The trans-opt files for modules within a
+        %   single SCC have to be made one after another.
+        % - The arbitrary ordering is likely to produce sub-optimal
+        %   information transfer between trans-opt files.
+        %
+        % To improve the situation, we allow the user to specify a file
+        % (see read_make_trans_opt_deps_spec) to manually remove edges in the
+        % dependency graph, thereby breaking up SCCs and, ideally, converting
+        % the graph into a dag.
+        globals.lookup_maybe_string_option(Globals,
+            make_trans_opt_deps_spec, MaybeSpecFileName),
+        (
+            MaybeSpecFileName = yes(SpecFileName),
+            read_make_trans_opt_deps_spec(SpecFileName, MaybeSpec, !IO),
+            (
+                MaybeSpec = ok(Spec),
+                remove_edges_for_make_trans_opt_deps(Spec,
+                    ImpDepsGraph, MakeTransOptDepsGraph0),
+                digraph.tc(MakeTransOptDepsGraph0, MakeTransOptDepsGraph)
+            ;
+                MaybeSpec = error(SpecError),
+                string.format("cannot parse %s: %s",
+                    [s(SpecFileName), s(SpecError)], SpecMessage),
+                report_error(ErrorStream, SpecMessage, !IO),
+                MakeTransOptDepsGraph = IndirectOptDepsGraph
+            )
+        ;
+            MaybeSpecFileName = no,
+            MakeTransOptDepsGraph = IndirectOptDepsGraph
+        ),
+        digraph.atsort(MakeTransOptDepsGraph, MakeTransOptDepsOrdering0),
+        maybe_output_module_order(Globals, ModuleName,
+            other_ext(".order-make-trans-opt"), MakeTransOptDepsOrdering0,
+            !IO),
+        list.map(set.to_sorted_list, MakeTransOptDepsOrdering0,
+            MakeTransOptDepsOrdering1),
+        list.condense(MakeTransOptDepsOrdering1, MakeTransOptDepsOrdering2),
+        globals.lookup_accumulating_option(Globals, intermod_directories,
+            IntermodDirs),
+        get_opt_deps(Globals, yes, IntermodDirs, other_ext(".trans_opt"),
+            MakeTransOptDepsOrdering2, MakeTransOptDepsOrdering, !IO),
+
         (
             Mode = output_d_file_only,
             DFilesToWrite = [ModuleDep]
@@ -253,7 +299,7 @@ generate_dependencies(Globals, Mode, Search, ModuleName, DepsMap0, !IO) :-
         generate_dependencies_write_d_files(Globals, DFilesToWrite,
             IntDepsGraph, ImpDepsGraph,
             IndirectDepsGraph, IndirectOptDepsGraph,
-            TransOptDepsOrdering, DepsMap, !IO)
+            MakeTransOptDepsGraph, MakeTransOptDepsOrdering, DepsMap, !IO)
     ),
 
     % For Java, the main target is actually a shell script which will set
@@ -418,6 +464,226 @@ write_edge(Stream, GenNodeName, A, B, !IO) :-
 sym_name_to_node_id(Name) =
     "\"" ++ sym_name_to_string(Name) ++ "\"".
 
+%---------------------------------------------------------------------------%
+
+:- type make_trans_opt_deps_spec == map(module_name, set(module_name)).
+
+    % The --make-trans-opts-deps-spec file shall contain a term of the form:
+    %
+    %   { PAIRS... }.
+    %
+    % where PAIRS is a comma-separated list of pairs:
+    %
+    %   M - { ALLOWED... }
+    %
+    % M is a Mercury module name.
+    % ALLOWED is a comma-separated list of module names.
+    %
+    % Such a pair specifies that for the module M,
+    % if it has a cyclic dependency on T,
+    % but T is not included in ALLOWED,
+    % then the edge M -> T is removed from the dependency graph
+    % for the purposes of making trans-opt files.
+    % In other words, in the process of making M.trans_opt,
+    % the compiler may not read T.trans_opt.
+    %
+    % To make the file less verbose, `builtin' and `private_builtin' are
+    % implicitly included in the ALLOWED list unless M is itself
+    % `builtin' or `private_builtin'.
+    %
+:- pred read_make_trans_opt_deps_spec(string::in,
+    maybe_error(make_trans_opt_deps_spec)::out, io::di, io::uo) is det.
+
+read_make_trans_opt_deps_spec(FileName, Result, !IO) :-
+    io.read_named_file_as_string(FileName, ReadResult, !IO),
+    (
+        ReadResult = ok(Contents),
+        read_term_from_string(FileName, Contents, _EndPos, ReadTerm),
+        (
+            ReadTerm = eof,
+            Result = error("expected term, got EOF")
+        ;
+            ReadTerm = error(Error, LineNum),
+            string.format("line %d: %s", [i(LineNum), s(Error)], Msg),
+            Result = error(Msg)
+        ;
+            ReadTerm = term(_VarSet, Term),
+            parse_make_trans_opt_deps_spec(Term, ParseResult, map.init, Spec),
+            (
+                ParseResult = ok,
+                % XXX check for EOF
+                Result = ok(Spec)
+            ;
+                ParseResult = error(Error),
+                Result = error(Error)
+            )
+        )
+    ;
+        ReadResult = error(Error),
+        Result = error(io.error_message(Error))
+    ).
+
+:- pred parse_make_trans_opt_deps_spec(term::in, maybe_error::out,
+    make_trans_opt_deps_spec::in, make_trans_opt_deps_spec::out) is det.
+
+parse_make_trans_opt_deps_spec(Term, Result, !Spec) :-
+    ( if Term = functor(atom("{}"), TermArgs, _Context) then
+        parse_make_trans_opt_deps_spec_pairs(TermArgs, Result, !Spec)
+    else
+        get_term_context(Term) = context(_FileName, LineNum),
+        string.format("line %d: expected {}", [i(LineNum)], Msg),
+        Result = error(Msg)
+    ).
+
+:- pred parse_make_trans_opt_deps_spec_pairs(list(term)::in, maybe_error::out,
+    make_trans_opt_deps_spec::in, make_trans_opt_deps_spec::out) is det.
+
+parse_make_trans_opt_deps_spec_pairs([], ok, !Spec).
+parse_make_trans_opt_deps_spec_pairs([Term | Terms], Result, !Spec) :-
+    parse_make_trans_opt_deps_spec_pair(Term, Result0, !Spec),
+    (
+        Result0 = ok,
+        parse_make_trans_opt_deps_spec_pairs(Terms, Result, !Spec)
+    ;
+        Result0 = error(Error),
+        Result = error(Error)
+    ).
+
+:- pred parse_make_trans_opt_deps_spec_pair(term::in, maybe_error::out,
+    make_trans_opt_deps_spec::in, make_trans_opt_deps_spec::out) is det.
+
+parse_make_trans_opt_deps_spec_pair(Term, Result, !Spec) :-
+    ( if
+        Term = functor(atom("-"), TermArgs, _Context),
+        TermArgs = [LeftTerm, RightTerm],
+        try_parse_symbol_name(LeftTerm, SourceName)
+    then
+        ( if
+            ( SourceName = unqualified("builtin")
+            ; SourceName = unqualified("private_builtin")
+            )
+        then
+            set.init(TargetSet0)
+        else
+            TargetSet0 = set.from_sorted_list(
+                [unqualified("builtin"), unqualified("private_builtin")])
+        ),
+        parse_make_trans_opt_deps_spec_target_set(RightTerm, Result0,
+            TargetSet0, TargetSet),
+        (
+            Result0 = ok,
+            ( if map.insert(SourceName, TargetSet, !Spec) then
+                Result = ok
+            else
+                get_term_context(Term) = context(_FileName, LineNum),
+                string.format("line %d: duplicate source module %s",
+                    [i(LineNum), s(sym_name_to_string(SourceName))], Msg),
+                Result = error(Msg)
+            )
+        ;
+            Result0 = error(Error),
+            Result = error(Error)
+        )
+    else
+        get_term_context(Term) = context(_FileName, LineNum),
+        string.format("line %d: expected -/2", [i(LineNum)], Msg),
+        Result = error(Msg)
+    ).
+
+:- pred parse_make_trans_opt_deps_spec_target_set(term::in, maybe_error::out,
+    set(module_name)::in, set(module_name)::out) is det.
+
+parse_make_trans_opt_deps_spec_target_set(Term, Result, !TargetSet) :-
+    ( if Term = functor(atom("{}"), TermArgs, _Context) then
+        foldl2(parse_make_trans_opt_deps_spec_target, TermArgs,
+            ok, Result0, [], TargetList),
+        (
+            Result0 = ok,
+            set.insert_list(TargetList, !TargetSet),
+            Result = ok
+        ;
+            Result0 = error(Error),
+            Result = error(Error)
+        )
+    else
+        get_term_context(Term) = context(_FileName, LineNum),
+        string.format("line %d: expected {}", [i(LineNum)], Msg),
+        Result = error(Msg)
+    ).
+
+:- pred parse_make_trans_opt_deps_spec_target(term::in,
+    maybe_error::in, maybe_error::out,
+    list(module_name)::in, list(module_name)::out) is det.
+
+parse_make_trans_opt_deps_spec_target(Term, !Result, !ModuleNames) :-
+    ( if try_parse_symbol_name(Term, ModuleName) then
+        !:ModuleNames = [ModuleName | !.ModuleNames]
+    else
+        (
+            !.Result = ok,
+            get_term_context(Term) = context(_FileName, LineNum),
+            string.format("line %d: expected module name", [i(LineNum)], Msg),
+            !:Result = error(Msg)
+        ;
+            !.Result = error(_)
+        )
+    ).
+
+%---------------------------------------------------------------------------%
+
+:- pred remove_edges_for_make_trans_opt_deps(make_trans_opt_deps_spec::in,
+    digraph(module_name)::in, digraph(module_name)::out) is det.
+
+remove_edges_for_make_trans_opt_deps(Spec, !Graph) :-
+    SCCs = set.to_sorted_list(digraph.cliques(!.Graph)),
+    map.foldl(remove_edges_for_make_trans_opt_deps_2(SCCs), Spec, !Graph).
+
+:- pred remove_edges_for_make_trans_opt_deps_2(
+    list(set(digraph_key(module_name)))::in,
+    module_name::in, set(module_name)::in,
+    digraph(module_name)::in, digraph(module_name)::out) is det.
+
+remove_edges_for_make_trans_opt_deps_2(SCCs, SourceName, AllowedTargets,
+        !Graph) :-
+    ( if
+        digraph.search_key(!.Graph, SourceName, SourceKey),
+        find_scc(SCCs, SourceKey, SCC),
+        set.count(SCC) > 1
+    then
+        set.foldl(
+            remove_edges_for_make_trans_opt_deps_3(SourceKey, AllowedTargets),
+            SCC, !Graph)
+    else
+        true
+    ).
+
+:- pred find_scc(list(set(digraph_key(module_name)))::in,
+    digraph_key(module_name)::in, set(digraph_key(module_name))::out)
+    is semidet.
+
+find_scc([SCC | SCCs], Module, FoundSCC) :-
+    ( if set.contains(SCC, Module) then
+        FoundSCC = SCC
+    else
+        find_scc(SCCs, Module, FoundSCC)
+    ).
+
+:- pred remove_edges_for_make_trans_opt_deps_3(digraph_key(module_name)::in,
+    set(module_name)::in, digraph_key(module_name)::in,
+    digraph(module_name)::in, digraph(module_name)::out) is det.
+
+remove_edges_for_make_trans_opt_deps_3(SourceKey, AllowedTargets, TargetKey,
+        !Graph) :-
+    ( if
+        SourceKey \= TargetKey,
+        digraph.lookup_vertex(!.Graph, TargetKey, TargetName),
+        not set.contains(AllowedTargets, TargetName)
+    then
+        digraph.delete_edge(SourceKey, TargetKey, !Graph)
+    else
+        true
+    ).
+
 %---------------------------------------------------------------------------%
 :- end_module parse_tree.generate_dep_d_files.
 %---------------------------------------------------------------------------%
diff --git a/compiler/options.m b/compiler/options.m
index 7d27b7819..def491228 100644
--- a/compiler/options.m
+++ b/compiler/options.m
@@ -387,6 +387,7 @@
     ;       show_developer_type_repns
     ;       show_dependency_graph
     ;       imports_graph
+    ;       make_trans_opt_deps_spec
     ;       dump_trace_counts
     ;       dump_hlds
     ;       dump_hlds_pred_id
@@ -1436,6 +1437,7 @@ optdef(oc_aux_output, show_all_type_repns,              bool(no)).
 optdef(oc_aux_output, show_developer_type_repns,        bool(no)).
 optdef(oc_aux_output, show_dependency_graph,            bool(no)).
 optdef(oc_aux_output, imports_graph,                    bool(no)).
+optdef(oc_aux_output, make_trans_opt_deps_spec,         maybe_string(no)).
 optdef(oc_aux_output, dump_trace_counts,                accumulating([])).
 optdef(oc_aux_output, dump_hlds,                        accumulating([])).
 optdef(oc_aux_output, dump_hlds_pred_id,                accumulating([])).
@@ -2388,6 +2390,7 @@ long_option("show-developer-type-repns",            show_developer_type_repns).
 long_option("show-developer-type-representations",  show_developer_type_repns).
 long_option("show-dependency-graph",    show_dependency_graph).
 long_option("imports-graph",            imports_graph).
+long_option("make-trans-opt-deps-spec", make_trans_opt_deps_spec).
 long_option("dump-trace-counts",        dump_trace_counts).
 long_option("dump-hlds",                dump_hlds).
 long_option("hlds-dump",                dump_hlds).
diff --git a/compiler/write_deps_file.m b/compiler/write_deps_file.m
index 6cb5cbcda..d74eb4da6 100644
--- a/compiler/write_deps_file.m
+++ b/compiler/write_deps_file.m
@@ -32,10 +32,11 @@
 :- type maybe_intermod_deps
     --->    no_intermod_deps
     ;       intermod_deps(
-                id_int_deps         :: set(module_name),
-                id_imp_deps         :: set(module_name),
-                id_indirect_deps    :: set(module_name),
-                id_fim_deps         :: set(module_name)
+                id_int_deps             :: set(module_name),
+                id_imp_deps             :: set(module_name),
+                id_indirect_deps        :: set(module_name),
+                id_fim_deps             :: set(module_name),
+                id_make_trans_opt_deps  :: set(module_name)
             ).
 
     % write_dependency_file(Globals, BurdenedAugCompUnit, MaybeIntermodDeps,
@@ -66,8 +67,8 @@
     maybe(list(module_name))::in, io::di, io::uo) is det.
 
     % generate_dependencies_write_d_files(Globals, Modules,
-    %   IntDepsRel, ImplDepsRel, IndirectDepsRel, IndirectOptDepsRel,
-    %   TransOptOrder, DepsMap, !IO):
+    %   IntDepsGraph, ImplDepsGraph, IndirectDepsGraph, IndirectOptDepsGraph,
+    %   MakeTransOptDepsGraph, TransOptOrder, DepsMap, !IO):
     %
     % This predicate writes out the .d files for all the modules in the
     % Modules list.
@@ -78,11 +79,15 @@
     % IndirectOptDepsGraph gives the indirect optimization dependencies
     % (this includes dependencies via `.opt' and `.trans_opt' files).
     % These are all computed from the DepsMap.
+    %
+    % MakeTransOptDepsGraph gives the trans-opt dependency graph for the
+    % purposes of making `.trans_opt' files.
     % TransOptOrder gives the ordering that is used to determine
     % which other modules the .trans_opt files may depend on.
     %
 :- pred generate_dependencies_write_d_files(globals::in, list(deps)::in,
     deps_graph::in, deps_graph::in, deps_graph::in, deps_graph::in,
+    deps_graph::in,
     list(module_name)::in, deps_map::in, io::di, io::uo) is det.
 
     % Write out the `.dv' file, using the information collected in the
@@ -97,7 +102,7 @@
 :- pred generate_dependencies_write_dep_file(globals::in, file_name::in,
     module_name::in, deps_map::in, io::di, io::uo) is det.
 
-:- pred maybe_output_module_order(globals::in, module_name::in,
+:- pred maybe_output_module_order(globals::in, module_name::in, other_ext::in,
     list(set(module_name))::in, io::di, io::uo) is det.
 
 %---------------------------------------------------------------------------%
@@ -283,7 +288,8 @@ generate_d_file(Globals, BurdenedAugCompUnit, IntermodDeps,
         IndirectIntSpecs = AugCompUnit ^ acu_indirect_int2_specs,
         map.keys_as_set(IndirectIntSpecs, IndirectDeps)
     ;
-        IntermodDeps = intermod_deps(IntDeps, ImpDeps, IndirectDeps, _FIMDeps),
+        IntermodDeps = intermod_deps(IntDeps, ImpDeps, IndirectDeps, _FIMDeps,
+            _MakeTransOptDeps),
         set.union(IntDeps, ImpDeps, LongDeps0)
     ),
     PublicChildrenMap = ParseTreeModuleSrc ^ ptms_int_includes,
@@ -303,10 +309,17 @@ generate_d_file(Globals, BurdenedAugCompUnit, IntermodDeps,
     set.difference(ShortDeps0, LongDeps, ShortDeps1),
     set.delete(ModuleName, ShortDeps1, ShortDeps),
 
+    (
+        IntermodDeps = no_intermod_deps,
+        MakeTransOptDeps = LongDeps
+    ;
+        IntermodDeps = intermod_deps(_, _, _, _, MakeTransOptDeps0),
+        set.delete(ModuleName, MakeTransOptDeps0, MakeTransOptDeps)
+    ),
     module_name_to_file_name(Globals, $pred, do_not_create_dirs,
-        ext_other(other_ext(".trans_opt_date")),
-        ModuleName, TransOptDateFileName, !IO),
-    construct_trans_opt_deps_rule(Globals, MaybeTransOptDeps, LongDeps,
+        ext_other(other_ext(".trans_opt_date")), ModuleName,
+        TransOptDateFileName, !IO),
+    construct_trans_opt_deps_rule(Globals, MaybeTransOptDeps, MakeTransOptDeps,
         TransOptDateFileName, MmakeRulesTransOpt, !IO),
 
     construct_fact_tables_entries(ModuleMakeVarName,
@@ -406,17 +419,25 @@ generate_d_file(Globals, BurdenedAugCompUnit, IntermodDeps,
     maybe(list(module_name))::in, set(module_name)::in, string::in,
     list(mmake_entry)::out, io::di, io::uo) is det.
 
-construct_trans_opt_deps_rule(Globals, MaybeTransOptDeps, LongDeps,
+construct_trans_opt_deps_rule(Globals, MaybeTransOptDeps, MakeTransOptDeps0,
         TransOptDateFileName, MmakeRulesTransOpt, !IO) :-
     (
-        MaybeTransOptDeps = yes(TransOptDeps0),
-        set.intersect(set.list_to_set(TransOptDeps0), LongDeps,
-            TransOptDateDeps),
+        MaybeTransOptDeps = yes(TransOptDeps),
+        % XXX TransOptDeps and MakeTransOptDeps0 are confusing and should
+        % be renamed.
+        %
+        % MakeTransOptDeps0 is what allows the user to remove edges from the
+        % trans-opt dependency graph.
+        %
+        % Taking the intersection with TransOptDeps removes any circularity
+        % that may remain.
+        set.intersect(set.list_to_set(TransOptDeps), MakeTransOptDeps0,
+            MakeTransOptDeps),
         % Note that maybe_read_dependency_file searches for
         % this exact pattern.
         make_module_file_names_with_suffix(Globals,
             ext_other(other_ext(".trans_opt")),
-            set.to_sorted_list(TransOptDateDeps), TransOptDateDepsFileNames,
+            set.to_sorted_list(MakeTransOptDeps), TransOptDateDepsFileNames,
             !IO),
         MmakeRuleTransOpt = mmake_simple_rule("trans_opt_deps",
             mmake_rule_is_not_phony,
@@ -850,7 +871,7 @@ construct_foreign_import_rules(Globals, AugCompUnit, IntermodDeps,
         _ModuleVersionNumber),
     ModuleName = ParseTreeModuleSrc ^ ptms_module_name,
     (
-        IntermodDeps = intermod_deps(_, _, _, ForeignImportedModuleNamesSet)
+        IntermodDeps = intermod_deps(_, _, _, ForeignImportedModuleNamesSet, _)
     ;
         IntermodDeps = no_intermod_deps,
         some [!FIMSpecs] (
@@ -1236,24 +1257,25 @@ construct_subdirs_shorthand_rule(Globals, ModuleName, OtherExt,
 
 %---------------------------------------------------------------------------%
 
-generate_dependencies_write_d_files(_, [], _, _, _, _, _, _, !IO).
+generate_dependencies_write_d_files(_, [], _, _, _, _, _, _, _, !IO).
 generate_dependencies_write_d_files(Globals, [Dep | Deps],
         IntDepsGraph, ImpDepsGraph, IndirectDepsGraph, IndirectOptDepsGraph,
-        TransOptOrder, DepsMap, !IO) :-
+        MakeTransOptDepsGraph, TransOptOrder, DepsMap, !IO) :-
     generate_dependencies_write_d_file(Globals, Dep,
         IntDepsGraph, ImpDepsGraph, IndirectDepsGraph, IndirectOptDepsGraph,
-        TransOptOrder, DepsMap, !IO),
+        MakeTransOptDepsGraph, TransOptOrder, DepsMap, !IO),
     generate_dependencies_write_d_files(Globals, Deps,
         IntDepsGraph, ImpDepsGraph, IndirectDepsGraph, IndirectOptDepsGraph,
-        TransOptOrder, DepsMap, !IO).
+        MakeTransOptDepsGraph, TransOptOrder, DepsMap, !IO).
 
 :- pred generate_dependencies_write_d_file(globals::in, deps::in,
     deps_graph::in, deps_graph::in, deps_graph::in, deps_graph::in,
-    list(module_name)::in, deps_map::in, io::di, io::uo) is det.
+    deps_graph::in, list(module_name)::in, deps_map::in, io::di, io::uo)
+    is det.
 
 generate_dependencies_write_d_file(Globals, Dep,
         IntDepsGraph, ImpDepsGraph, IndirectDepsGraph, IndirectOptDepsGraph,
-        TransOptOrder, _DepsMap, !IO) :-
+        MakeTransOptDepsGraph, TransOptOrder, _DepsMap, !IO) :-
     % XXX The fact that _DepsMap is unused here may be a bug.
     Dep = deps(_, BurdenedModule),
     BurdenedModule = burdened_module(Baggage, ParseTreeModuleSrc),
@@ -1284,8 +1306,11 @@ generate_dependencies_write_d_file(Globals, Dep,
             IndirectDeps)
     ),
 
+    get_dependencies_from_graph(MakeTransOptDepsGraph, ModuleName,
+        MakeTransOptDeps),
+
     IntermodDeps = intermod_deps(IntDeps, ImpDeps, IndirectDeps,
-        IndirectOptDeps),
+        IndirectOptDeps, MakeTransOptDeps),
 
     % Compute the trans-opt dependencies for this module. To avoid
     % the possibility of cycles, each module is only allowed to depend
@@ -2407,12 +2432,12 @@ get_source_file(DepsMap, ModuleName, FileName) :-
 
 %---------------------------------------------------------------------------%
 
-maybe_output_module_order(Globals, ModuleName, DepsOrdering, !IO) :-
+maybe_output_module_order(Globals, ModuleName, Ext, DepsOrdering, !IO) :-
     globals.lookup_bool_option(Globals, generate_module_order, Order),
     (
         Order = yes,
         module_name_to_file_name(Globals, $pred, do_create_dirs,
-            ext_other(other_ext(".order")), ModuleName, OrdFileName, !IO),
+            ext_other(Ext), ModuleName, OrdFileName, !IO),
         get_progress_output_stream(Globals, ModuleName, ProgressStream, !IO),
         globals.lookup_bool_option(Globals, verbose, Verbose),
         string.format("%% Creating module order file `%s'...",
diff --git a/doc/user_guide.texi b/doc/user_guide.texi
index 82ee78a65..8c76955c0 100644
--- a/doc/user_guide.texi
+++ b/doc/user_guide.texi
@@ -201,14 +201,14 @@ generates both @file{.int} and @file{.int2} files.)
 @findex --make-private-interface
 @findex --make-optimization-interface
 @findex --make-transitive-optimization-interface
- at findex --make-trans-opt-int
+ at findex --make-trans-opt
 Files whose names end in @file{.opt} are used for inter-module optimization,
 and are created using the @samp{--make-optimization-interface}
 (or @samp{--make-opt-int}) option.
 Similarly, files whose name ends in @file{.trans_opt}
 are used for transitive inter-module optimization,
 and are created using the @samp{--make-transitive-optimization-interface}
-(or @samp{--make-trans-opt-int}) option.
+(or @samp{--make-trans-opt}) option.
 
 Since the interface of a module changes less often than its implementation,
 the @file{.int}, @file{.int0}, @file{.int2}, @file{.int3}, @file{.opt},
-------------- next part --------------
{
  private_builtin - {},
  builtin - {
    private_builtin
  },

  array - {
    exception,
    int,
    list,
    %pretty_printer,
    require,
    string,
    type_desc
  },
  /*
  assoc_list - {
    list,
    pair,
    require,
    string,
    type_desc
  },
  benchmarking - {
    bool,
    int,
    io,
    list,
    maybe,
    mutvar,
    require,
    string
  },
  */
  bitmap - {
    bool,
    char,
    exception,
    int,
    %io,    % write_bitmap becomes can_loop
    list,
    maybe,
    require,
    stream,
    string
  },
  /*
  bool - {
    enum,
    list
  },
  calendar - {
    char,
    int,
    io,
    list,
    require,
    string,
    time
  },
  */
  char - {
    enum,
    int,
    list,
    %pretty_printer,
    require,
    %term_io,
    uint,
    uint16,
    uint8
  },
  /*
  construct - {
    int,
    list,
    maybe,
    require,
    rtti_implementation,
    type_desc,
    univ
  },
  cord - {
    int,
    list
  },
  deconstruct - {
    construct,
    int,
    list,
    maybe,
    require,
    rtti_implementation,
    type_desc,
    univ
  },
  dir - {
    bool,
    char,
    exception,
    int,
    io,
    io.file,
    list,
    maybe,
    require,
    std_util,
    string,
    unit
  },
  enum - {
    require
  },
  */
  exception - {
    %io,
    %list,
    maybe,
    %solutions,
    %stm_builtin,
    %store,
    %string,
    unit,
    univ
  },
  float - {
    exception,
    int,
    %pretty_printer,
    string
  },
  int - {
    %array,
    enum,
    %exception,
    %pretty_printer,
    %string,
    uint
  },
  int16 - {
    %exception,
    int,
    %pretty_printer,
    require,
    %string,
    uint,
    uint16
  },
  int32 - {
    %exception,
    int,
    %pretty_printer,
    require,
    %string,
    uint,
    uint32
  },
  int64 - {
    %exception,
    int,
    %pretty_printer,
    require,
    %string,
    uint,
    uint64
  },
  int8 - {
    %exception,
    int,
    %pretty_printer,
    require,
    %string,
    uint,
    uint8
  },
  /*
  integer - {
    char,
    exception,
    float,
    int,
    int16,
    int32,
    int64,
    int8,
    list,
    require,
    string,
    uint,
    uint16,
    uint32,
    uint64,
    uint8
  },
  */
  io - {
    array,
    %benchmarking,
    bitmap,
    bool,
    char,
    deconstruct,
    %dir,
    exception,
    int,
    int16,
    int32,
    int64,
    int8,
    io.call_system,
    io.environment,
    io.file,
    io.primitives_read,
    io.primitives_write,
    io.stream_db,
    io.stream_ops,
    io.text_read,
    list,
    map,
    maybe,
    %mercury_term_parser,
    require,
    rtti_implementation,
    stream,
    %stream.string_writer,
    string,
    table_builtin,
    term,
    term_conversion,
    term_subst,
    time,
    type_desc,
    uint16,
    uint32,
    uint64,
    uint8,
    univ
  },
  io.call_system - {
    string
  },
  io.environment - {
    assoc_list,
    list,
    map,
    maybe,
    pair
  },
  io.file - {
    io.environment,
    time
  },
  io.primitives_read - {
    char
  },
  io.primitives_write - {
    char
  },
  io.stream_db - {
    map,
    maybe
  },
  io.stream_ops - {
    % deletes some implicit deps from parent module
  },
  io.text_read - {
    array,
    bitmap,
    char,
    int,
    int64,
    io.primitives_read,
    list
  },
  list - {
    int,
    %pretty_printer,
    require
    %set_tree234,
    %string,
    %term
  },
  map - {
    assoc_list,
    int,
    list,
    maybe,
    pair,
    require,
    set,
    %term,
    tree234
  },
  maybe - {
    %list
  },
  /*
  mercury_term_lexer - {
    char,
    int,
    integer,
    io,
    list,
    require,
    string
  },
  mercury_term_parser - {
    bool,
    char,
    float,
    integer,
    io,
    list,
    map,
    maybe,
    mercury_term_lexer,
    ops,
    require,
    string,
    term,
    term_context,
    uint,
    varset
  },
  ops - {
    require,
    uint
  },
  pretty_printer - {
    array,
    bool,
    char,
    deconstruct,
    float,
    int,
    io,
    list,
    map,
    ops,
    require,
    stream,
    string,
    term_io,
    tree234,
    type_desc,
    uint,
    univ,
    version_array
  },
  */

  % It is useful to keep 'require' and 'exception' low in the order
  % to improves termination/exception analysis for many modules.
  require - {
    exception
    %list,
    %string,
    %type_desc
  },
  rtti_implementation - {
    array,
    bitmap,
    bool,
    char,
    %deconstruct,
    int,
    int16,
    int32,
    list,
    maybe,
    require,
    string,
    %term_io,
    type_desc,
    univ
  },
  set - {
    bool,
    list,
    require,
    set_ordlist
    %term
  },
  set_ordlist - {
    bool,
    cord,
    list,
    require
    %term
  },
  set_tree234 - {
    bool,
    cord,
    int,
    list,
    require,
    set,
    string
    %term
  },
  /*
  solutions - {
    bool,
    list,
    mutvar,
    require,
    set
  },
  std_util - {
    int
  },
  stm_builtin - {
    exception,
    io,
    univ
  },
  store - {
    deconstruct,
    io,
    require
  },
  stream - {
    bool,
    char,
    list
  },
  */
  stream.string_writer - {
    array,
    bitmap,
    %calendar,
    char,
    deconstruct,
    int,
    integer,
    io,
    io.stream_db,
    list,
    ops,
    require,
    rtti_implementation,
    string,
    %term_io,
    type_desc,
    univ,
    version_array
  },
  string - {
    %assoc_list,
    bool,
    char,
    %deconstruct,
    int,
    list,
    maybe,
    %ops,
    pair,
    %pretty_printer,
    require,
    %string.format,
    %string.to_string,
    %term_io,
    uint,
    uint8
  },
  string.format - {
    % deletes some implicit dep
    bool,
    exception,
    float,
    int,
    int16,
    int32,
    int64,
    int8,
    integer,
    list,
    require,
    string.parse_runtime,
    string.parse_util,
    uint,
    uint16,
    uint32,
    uint64,
    uint8
  },
  string.parse_runtime - {
    % deletes some implicit dep
    int,
    list,
    string.parse_util
  },
  string.parse_util - {
    % deletes some implicit dep
    int,
    list
  },
  /*
  string.to_string - {
    array,
    bitmap,
    deconstruct,
    int,
    ops,
    rtti_implementation,
    term_io,
    type_desc,
    univ,
    version_array
  },
  */
  table_builtin - {
    %io,
    require,
    univ
  },
  /*
  term - {
    enum,
    int,
    integer,
    list,
    map,
    term_context,
    term_int,
    term_subst,
    term_unify,
    term_vars,
    uint
  },
  term_conversion - {
    array,
    bitmap,
    construct,
    deconstruct,
    int,
    integer,
    list,
    require,
    string,
    term,
    term_context,
    term_int,
    term_subst,
    type_desc,
    univ,
    version_array
  },
  */
  term_int - {
    integer,
    list
    %term
  },
  /*
  term_io - {
    bool,
    char,
    int,
    integer,
    io,
    list,
    mercury_term_lexer,
    ops,
    stream,
    stream.string_writer,
    string,
    term,
    varset
  },
  */
  term_subst - {
    list,
    map,
    require,
    %term,
    term_context
  },
  term_unify - {
    list,
    map,
    %term,
    term_context,
    term_subst,
    term_vars
  },
  term_vars - {
    list
    %term
  },
  time - {
    bool,
    exception,
    int,
    %io,
    list,
    maybe,
    require,
    string
  },
  tree234 - {
    assoc_list,
    bool,
    int,
    %io,
    list,
    maybe,
    pair,
    %pretty_printer,
    require,
    set,
    string
    %term
  },
  type_desc - {
    list,
    require,
    %rtti_implementation,
    string
  },
  uint - {
    enum,
    exception,
    %pretty_printer,
    require
    %string
  },
  uint16 - {
    exception,
    int,
    %pretty_printer,
    require,
    %string,
    uint
  },
  uint32 - {
    exception,
    int,
    %pretty_printer,
    require,
    %string,
    uint
  },
  uint64 - {
    exception,
    int,
    %pretty_printer,
    require,
    %string,
    uint
  },
  uint8 - {
    exception,
    int,
    %pretty_printer,
    require,
    %string,
    uint
  },
  univ - {
    %list,
    %require,   % either require or univ needs to lower than the other
    %string,
    %type_desc
  },
  /*
  varset - {
    assoc_list,
    int,
    list,
    map,
    maybe,
    pair,
    require,
    set,
    string,
    term,
    term_subst
  },
  */
  version_array - {
    exception,
    int,
    list,
    %pretty_printer,
    string
  }
}.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: results.txt.gz
Type: application/gzip
Size: 8960 bytes
Desc: not available
URL: <http://lists.mercurylang.org/archives/reviews/attachments/20221219/61555ac0/attachment-0001.gz>


More information about the reviews mailing list