[m-rev.] for review: Add --trans-opt-deps-spec option.

Peter Wang novalazy at gmail.com
Thu Jan 12 16:57:16 AEDT 2023


On Thu, 12 Jan 2023 15:14:59 +1100 "Zoltan Somogyi" <zoltan.somogyi at runbox.com> wrote:
> 
> 2023-01-12 14:13 GMT+11:00 "Peter Wang" <novalazy at gmail.com>:
> > This option lets the user provide a file containing information to
> > remove some edges from the trans-opt dependency graph, i.e. the graph
> > used to determine which .trans_opt files to read when making a module's
> > own .trans_opt file.
> > 
> > The reason to remove edges from the graph is to break dependency cycles.
> > .trans_opt files for modules within an SCC have to be made one after
> > another, instead of in parallel. For example, the standard library
> > contains one large SCC due to circular imports, so making .trans_opt
> > files turns out to be a bottleneck when building the standard library
> > (on a machine with sufficient parallelism available).
> > 
> > Furthermore, the user had no control over which modules in an SCC
> > could read the .trans_opt files of other modules in the same SCC.
> > If a and b happened to import each other, the compiler would always
> > break the cycle by allowing a to read b.trans_opt, but not allow b to
> > read a.trans_opt, simply based on module names. The new option lets the
> > user break the cycle in a way that may improve analysis results.
> > 
> > compiler/options.m:
> >     Add the --trans-opt-deps-spec option.
> > 
> > compiler/generate_dep_d_files.m:
> >     If the option --trans-opt-deps-spec FILE is used, use the
> >     information given in the file to remove some edges from the
> >     trans-opt dependency graph.
> > 
> >     If --generate-module-order is passed, also output the module order
> >     computed from the trans-opt dependency graph to a file. This can be
> >     use to guide the writing of the spec file.
> 
> I would reword the last sentence, to something like this:
> 
> Users may find this a useful starting point when writing their own spec file.
> 

Done.

> > +    % The --trans-opt-deps-spec file shall contain a series of terms
> > +    % of either form:
> > +    %
> > +    %   module_allow_deps(M, [ ALLOW ]).
> > +    %   module_disallow_deps(M, [ DISALLOW ]).
> > +    %
> > +    % where M is a Mercury module name,
> > +    % and ALLOW and DISALLOW are comma-separated lists of module names.
> > +    %
> > +    % To make the file less verbose, `builtin' and `private_builtin' are
> > +    % implicitly included in an ALLOW list unless M is itself `builtin'
> > +    % or `private_builtin'.
> 
> I don't think we discussed this earlier, but I think it is worth considering
> whether this policy should be extended either 
> 
> - to all the library modules whose names contain "builtin". or
> - to all the library modules that the compiler can consider a module to depend on
>   implicitly, which includes all the "x_builtin" modules, but also the others that
>   can be returned by compute_implicit_avail_needs in get_dependencies.m.
> 

Hmm, perhaps.

> > +    % TODO: report errors using error specs
> > +    % TODO: report multiple errors
> 
> If you want, I can do these after you commit.
> 

That will be helpful, thanks.

> > +:- pred parse_trans_opt_deps_spec_term(term::in, maybe_error::out,
> > +    trans_opt_deps_spec::in, trans_opt_deps_spec::out) is det.
> > +
> > +parse_trans_opt_deps_spec_term(Term, Result, !SpecFile) :-
> > +    ( if
> > +        Term = functor(atom(AtomName), [LeftTerm, RightTerm], _Context),
> > +        (
> > +            AtomName = "module_allow_deps"
> > +        ;
> > +            AtomName = "module_disallow_deps"
> > +        ),
> > +        try_parse_symbol_name(LeftTerm, SourceName)
> > +    then
> > +        ( if
> > +            AtomName = "module_allow_deps",
> > +            SourceName \= unqualified("builtin"),
> > +            SourceName \= unqualified("private_builtin")
> > +        then
> > +            TargetList0 = [
> > +                unqualified("builtin"),
> > +                unqualified("private_builtin")
> > +            ]
> > +        else
> > +            TargetList0 = []
> > +        ),
> > +        parse_trans_opt_deps_spec_module_list(RightTerm, Result0,
> > +            TargetList0, TargetList),
> > +        (
> > +            Result0 = ok,
> > +            set.list_to_set(TargetList, TargetSet),
> > +            (
> > +                AtomName = "module_allow_deps",
> > +                AllowOrDisallow = module_allow_deps(TargetSet)
> > +            ;
> > +                AtomName = "module_disallow_deps",
> > +                AllowOrDisallow = module_disallow_deps(TargetSet)
> > +            ),
> 
> This code seems to include builtin and private_builtin automatically
> in DISALLOW lists, as well as ALLOW lists.

TargetList0 = [] unless AtomName = "module_allow_deps".

But I've simplified the code anyway.

> > diff --git a/compiler/mercury_compile_make_hlds.m b/compiler/mercury_compile_make_hlds.m
> > index 5b61cbf7e..afe5af779 100644
> > --- a/compiler/mercury_compile_make_hlds.m
> > +++ b/compiler/mercury_compile_make_hlds.m
> 
> > @@ -489,14 +498,14 @@ maybe_grab_plain_and_trans_opt_files(ProgressStream, ErrorStream, Globals,
> >      (
> >          OpModeAugment = opmau_make_trans_opt,
> >          (
> > -            MaybeTransOptDeps = yes(TransOptDeps),
> > +            MaybeDFileTransOptDeps = yes(DFileTransOptDeps),
> >              % When creating the trans_opt file, only import the
> > -            % trans_opt files which are lower in the ordering.
> > +            % trans_opt files which are listed in the `.d' file.
> 
> "listed in the .d file" means "anywhere in the .d file". Is this what you
> want to say?
> 

I have expanded that to:

    % When creating the trans_opt file, only import the
    % trans_opt files which are listed as dependencies of the
    % trans_opt_deps rule in the `.d' file.

> > +            TransOptRuleInfo = trans_opt_deps_from_d_file(DFileTransOptDeps),
> > +            TransOptDeps = DFileTransOptDeps
> > +        ),
> >          % 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(TransOptDeps), TransOptDepsFileNames,
> >              !IO),
> 
> This change seems strange, but it seems that the original variable name
> was simply badly chosen.
> 

Perhaps it was intended as "the deps of the trans_opt_date rule"?

I've followed your other suggestions, thanks.

I've attached the spec file I'm working on, in case it will be helpful to
you.

Peter
-------------- next part --------------
module_allow_deps(private_builtin, []).
module_allow_deps(builtin, [private_builtin]).

%--------------------------------------%

module_disallow_deps(univ, [
    list,
    require,
    string,
    type_desc
    ]).

module_disallow_deps(exception, [
    io,
    list,
    solutions,
    stm_builtin,
    store,
    string
    ]).

module_disallow_deps(require, [
    enum,
    list,
    string,
    string.format,
    string.parse_util,
    type_desc
    ]).

%--------------------------------------%

module_disallow_deps(int, [
    array,              % only for modes
    pretty_printer
    ]).
module_disallow_deps(int16, [pretty_printer]).
module_disallow_deps(int32, [pretty_printer]).
module_disallow_deps(int64, [pretty_printer]).
module_disallow_deps(int8, [pretty_printer]).

module_disallow_deps(uint, [pretty_printer]).
module_disallow_deps(uint16, [pretty_printer]).
module_disallow_deps(uint32, [pretty_printer]).
module_disallow_deps(uint64, [pretty_printer]).
module_disallow_deps(uint8, [pretty_printer]).

module_disallow_deps(array, [
    pretty_printer,
    string.format,
    string.parse_runtime,
    string.parse_util,
    type_desc           % only for dynamic_cast_to_array
    ]).

module_disallow_deps(char, [pretty_printer]).
module_disallow_deps(float, [pretty_printer]).
module_disallow_deps(one_or_more, [pretty_printer]).
module_disallow_deps(version_array, [pretty_printer]).

%--------------------------------------%

module_disallow_deps(rtti_implementation, [
    bitmap,
    deconstruct,
    string.format,
    string.parse_runtime,
    string.parse_util,
    term_io,            % only for term_io.quoted_string
    type_desc
    ]).

module_disallow_deps(type_desc, []).

%--------------------------------------%

module_disallow_deps(maybe, [list]).
module_disallow_deps(list, [
    pretty_printer,
    set_tree234,
    string,
    term
    ]).

%--------------------------------------%

module_disallow_deps(string, [
    assoc_list,
    deconstruct,
    pretty_printer,
    string.format,
    string.parse_util,
    string.to_string
    ]).
module_disallow_deps(string.parse_util, [
    deconstruct,
    pretty_printer,
    string.format,
    string.to_string
    ]).
module_disallow_deps(string.parse_runtime, [
    deconstruct,
    pretty_printer,
    string.format,
    string.to_string
    ]).
module_disallow_deps(string.format, [
    deconstruct,
    pretty_printer,
    string.to_string
    ]).
module_disallow_deps(string.to_string, []).

%--------------------------------------%

module_disallow_deps(tree234, [
    io,                 % only for trace goals
    pretty_printer,
    term                % only for var type
    ]).

module_disallow_deps(map, [term]).
module_disallow_deps(set, [term]).
module_disallow_deps(set_ordlist, [term]).
module_disallow_deps(set_tree234, [term]).

module_disallow_deps(term, [
    term_int,
    term_subst,
    term_unify,
    term_vars
    ]).

module_disallow_deps(term_conversion, [bitmap]).

%--------------------------------------%

% These only import io for the io.state.
module_disallow_deps(table_builtin, [io]).
module_disallow_deps(time, [io]).

% io.file, io.environment and io.call_system have nothing to do with
% stream I/O.
module_disallow_deps(io.file, [
    benchmarking,
    bitmap,
    dir,
    mercury_term_parser,
    stream.string_writer,
    io,                 % XXX move is_error, etc.
    io.call_system,
    io.environment,
    io.primitives_read,
    io.primitives_write,
    io.stream_db,
    io.stream_ops,
    io.text_read
    ]).
module_disallow_deps(io.environment, [
    benchmarking,
    bitmap,
    dir,
    mercury_term_parser,
    stream.string_writer,
    io,
    io.call_system,
    io.file,
    io.primitives_read,
    io.primitives_write,
    io.stream_db,
    io.stream_ops,
    io.text_read
    ]).
module_disallow_deps(io.call_system, [
    benchmarking,
    bitmap,
    dir,
    mercury_term_parser,
    stream.string_writer,
    io,
    io.environment,
    io.file,
    io.primitives_read,
    io.primitives_write,
    io.stream_db,
    io.stream_ops,
    io.text_read
    ]).

module_disallow_deps(io.stream_db, [
    benchmarking,
    bitmap,
    dir,
    mercury_term_parser,
    stream.string_writer,
    io,
    io.primitives_read,
    io.primitives_write,
    io.stream_ops,
    io.text_read
    ]).
module_disallow_deps(io.stream_ops, [
    benchmarking,
    bitmap,
    dir,
    mercury_term_parser,
    stream.string_writer,
    io,
    io.stream_db,
    io.primitives_read,
    io.primitives_write,
    io.text_read
    ]).
module_disallow_deps(io.primitives_read, [
    benchmarking,
    bitmap,
    dir,
    mercury_term_parser,
    stream.string_writer,
    io,
    io.primitives_write,
    io.text_read
    ]).
module_disallow_deps(io.primitives_write, [
    benchmarking,
    bitmap,
    dir,
    mercury_term_parser,
    stream.string_writer,
    io,
    io.primitives_read,
    io.text_read
    ]).
module_disallow_deps(io, [
    benchmarking,
    bitmap,
    dir,
    mercury_term_parser,
    stream.string_writer,
    io.text_read,
    type_desc       % only for gc_init
    ]).
module_disallow_deps(io.text_read, []).

% term_io calls stream.string_writer.maybe_write_paren.
% stream.string_writer calls term_io.quote_X.
module_disallow_deps(term_io, [stream.string_writer]).
module_disallow_deps(stream.string_writer, []).

%--------------------------------------%


More information about the reviews mailing list