mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-22 21:03:53 +00:00
Both ml_code_util.m and ml_call_gen.m had predicates that used the same logic
to process lists of arguments. This is not a coincidence; they both process
argument lists, one from the point of the callee, the other from the point
of view of the caller. These have to be kept in lockstep. This is easier
if they are next to each other. This diff therefore moves those predicates
to the same module, a new module named ml_args_util.m.
compiler/ml_call_gen.m:
compiler/ml_code_util.m:
Delete the new code now in ml_args_util.m.
compiler/ml_args_util.m:
The new module.
compiler/ml_backend.m:
compiler/notes/compiler_design.html:
Mention the new module.
compiler/ml_closure_gen.m:
compiler/ml_proc_gen.m:
compiler/ml_top_gen.m:
compiler/rtti_to_mlds.m:
Conform to the changes above.
2431 lines
80 KiB
HTML
2431 lines
80 KiB
HTML
<html>
|
|
<head>
|
|
<title>
|
|
Notes On The Design Of The Mercury Compiler
|
|
</title>
|
|
</head>
|
|
|
|
<body bgcolor="#ffffff" text="#000000">
|
|
|
|
<hr>
|
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
|
|
<p>
|
|
This file contains an overview of the design of the compiler.
|
|
|
|
<p>
|
|
See also <a href="overall_design.html">overall_design.html</a>
|
|
for an overview of how the different sub-systems (compiler,
|
|
library, runtime, etc.) fit together.
|
|
|
|
<hr>
|
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
|
|
<h2> OUTLINE </h2>
|
|
|
|
<p>
|
|
|
|
The main job of the compiler is to translate Mercury into C, although it
|
|
can also translate (subsets of) Mercury to some other languages:
|
|
Mercury bytecode (for a planned bytecode interpreter), C#, Java and Erlang.
|
|
|
|
<p>
|
|
|
|
The top-level of the compiler is in the file mercury_compiler.m.
|
|
This forwards all of the work to the file mercury_compiler_main.m which is a
|
|
sub-module of the top_level.m package.
|
|
The basic design is that compilation is broken into the following
|
|
stages:
|
|
|
|
<ul>
|
|
<li>
|
|
1. parsing (source files -> HLDS)
|
|
<li>
|
|
2. semantic analysis and error checking (HLDS -> annotated HLDS)
|
|
<li>
|
|
3. high-level transformations (annotated HLDS -> annotated HLDS)
|
|
<li>
|
|
4. code generation (annotated HLDS -> target representation)
|
|
<li>
|
|
5. low-level optimizations
|
|
(target representation -> target representation)
|
|
<li>
|
|
6. output code (target representation -> target code)
|
|
</ul>
|
|
|
|
<p>
|
|
Note that in reality the separation is not quite as simple as that.
|
|
Although parsing is listed as step 1 and semantic analysis is listed
|
|
as step 2, the last stage of parsing actually includes some semantic checks.
|
|
And although optimization is listed as steps 3 and 5, it also occurs in
|
|
steps 2, 4, and 6. For example, elimination of assignments to dead
|
|
variables is done in mode analysis; middle-recursion optimization and
|
|
the use of static constants for ground terms is done during code generation;
|
|
and a few low-level optimizations are done in llds_out.m
|
|
as we are spitting out the C code.
|
|
|
|
<p>
|
|
|
|
In addition, the compiler is actually a multi-targeted compiler
|
|
with several different back-ends.
|
|
|
|
<p>
|
|
|
|
mercury_compile.m itself supervises the parsing (step 1),
|
|
but it subcontracts the supervision of the later steps to other modules.
|
|
Semantic analysis (step 2) is looked after by mercury_compile_front_end.m;
|
|
high level transformations (step 3) by mercury_compile_middle_passes.m;
|
|
and code generation, optimization and output (steps 4, 5 and 6)
|
|
by mercury_compile_llds_backend.m, mercury_compile_mlds_backend.m
|
|
and mercury_compile_erl_backend.m
|
|
for the LLDS, MLDS and Erlang backends respectively.
|
|
|
|
<p>
|
|
|
|
The modules in the compiler are structured by being grouped into "packages".
|
|
A "package" is just a meta-module,
|
|
i.e. a module that contains other modules as sub-modules.
|
|
(The sub-modules are almost always stored in separate files,
|
|
which are named only for their final module name.)
|
|
We have a package for the top-level, a package for each main pass, and
|
|
finally there are also some packages for library modules that are used
|
|
by more than one pass.
|
|
<p>
|
|
|
|
Taking all this into account, the structure looks like this:
|
|
|
|
<ul type=disc>
|
|
<li>
|
|
At the top of the dependency graph is the top_level.m package,
|
|
which currently contains only the mercury_compile*.m modules,
|
|
which invoke all the different passes in the compiler.
|
|
<li>
|
|
The next level down is all of the different passes of the compiler.
|
|
In general, we try to stick by the principle that later passes can
|
|
depend on data structures defined in earlier passes, but not vice versa.
|
|
<ul type=disc>
|
|
<li>
|
|
front-end
|
|
<ul type=disc>
|
|
<li>
|
|
1. parsing (source files -> HLDS)
|
|
<br>
|
|
Packages: parse_tree.m and hlds.m
|
|
<li>
|
|
2. semantic analysis and error checking (HLDS -> annotated HLDS)
|
|
<br>
|
|
Package: check_hlds.m
|
|
<li>
|
|
3. high-level transformations (annotated HLDS -> annotated HLDS)
|
|
<br>
|
|
Packages: transform_hlds.m and analysis.m
|
|
</ul>
|
|
<li>
|
|
back-ends
|
|
<ul type=disc>
|
|
<li>
|
|
a. LLDS back-end
|
|
<br>
|
|
Package: ll_backend.m
|
|
<ul type=disc>
|
|
<li>
|
|
3a. LLDS-back-end-specific HLDS->HLDS transformations
|
|
<li>
|
|
4a. code generation (annotated HLDS -> LLDS)
|
|
<li>
|
|
5a. low-level optimizations (LLDS -> LLDS)
|
|
<li>
|
|
6a. output code (LLDS -> C)
|
|
</ul>
|
|
<li>
|
|
b. MLDS back-end
|
|
<br>
|
|
Package: ml_backend.m
|
|
<ul type=disc>
|
|
<li>
|
|
4b. code generation (annotated HLDS -> MLDS)
|
|
<li>
|
|
5b. MLDS transformations (MLDS -> MLDS)
|
|
<li>
|
|
6b. output code
|
|
(MLDS -> C or MLDS -> C# or MLDS -> Java, etc.)
|
|
</ul>
|
|
<li>
|
|
c. bytecode back-end
|
|
<br>
|
|
Package: bytecode_backend.m
|
|
<ul type=disc>
|
|
<li>
|
|
4c. code generation (annotated HLDS -> bytecode)
|
|
</ul>
|
|
<li>
|
|
d. Erlang back-end
|
|
<br>
|
|
Package: erl_backend.m
|
|
<ul type=disc>
|
|
<li>
|
|
4d. code generation (annotated HLDS -> ELDS)
|
|
<li>
|
|
6d. output code (ELDS -> Erlang)
|
|
</ul>
|
|
<li>
|
|
There is also a package backend_libs.m which contains modules
|
|
which are shared between several different back-ends.
|
|
</ul>
|
|
</ul>
|
|
<li>
|
|
Finally, at the bottom of the dependency graph there is the package libs.m.
|
|
libs.m contains the option handling code, and also library modules
|
|
which are not sufficiently general or sufficiently useful to go
|
|
in the Mercury standard library.
|
|
</ul>
|
|
|
|
<p>
|
|
|
|
In addition to the packages mentioned above, there are also packages
|
|
for the build system: make.m contains the support for the `--make' option,
|
|
and recompilation.m contains the support for the `--smart-recompilation'
|
|
option.
|
|
|
|
<hr>
|
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
|
|
<h2> DETAILED DESIGN </h2>
|
|
|
|
<p>
|
|
This section describes the role of each module in the compiler.
|
|
For more information about the design of a particular module,
|
|
see the documentation at the start of that module's source code.
|
|
|
|
<hr>
|
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
<p>
|
|
|
|
The action is co-ordinated from mercury_compile.m or make.m (if `--make'
|
|
was specified on the command line).
|
|
|
|
<h3> Option handling </h3>
|
|
|
|
<p>
|
|
|
|
Option handling is part of the libs.m package.
|
|
|
|
<p>
|
|
|
|
The command-line options are defined in the module options.m.
|
|
mercury_compile.m calls library/getopt_io.m, passing the predicates
|
|
defined in options.m as arguments, to parse them. It then invokes
|
|
handle_options.m (and indirectly, op_mode.m and compute_grade.m)
|
|
to postprocess the option set.
|
|
The results are represented using the type globals, defined in globals.m.
|
|
The globals structure is available in the HLDS representation,
|
|
but it is passed around as a separate argument both before the HLDS is built
|
|
and after it is no longer needed.
|
|
|
|
<h3> Build system </h3>
|
|
|
|
<p>
|
|
|
|
Support for `--make' is in the make.m package,
|
|
which contains the following modules:
|
|
|
|
<dl>
|
|
|
|
<dt> make.m
|
|
<dd>
|
|
Categorizes targets passed on the command line and passes
|
|
them to the appropriate module to be built.
|
|
|
|
<dt> make.program_target.m
|
|
<dd>
|
|
Handles whole program `mmc --make' targets, including
|
|
executables, libraries and cleanup.
|
|
|
|
<dt> make.module_target.m
|
|
<dd>
|
|
Handles targets built by a compilation action associated
|
|
with a single module, for example making interface files.
|
|
|
|
<dt> make.dependencies.m
|
|
<dd>
|
|
Compute dependencies between targets and between modules.
|
|
|
|
<dt> make.module_dep_file.m
|
|
<dd>
|
|
Record the dependency information for each module between compilations.
|
|
|
|
<dt> make.util.m
|
|
<dd>
|
|
Utility predicates.
|
|
|
|
<dt> options_file.m
|
|
<dd>
|
|
Read the options files specified by the `--options-file' option.
|
|
Also used by mercury_compile.m to collect the value of DEFAULT_MCFLAGS,
|
|
which contains the auto-configured flags passed to the compiler.
|
|
|
|
</dl>
|
|
|
|
The build process also invokes routines in compile_target_code.m,
|
|
which is part of the backend_libs.m package (see below).
|
|
|
|
<p>
|
|
<hr>
|
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
|
|
<h3> FRONT END </h3>
|
|
<h4> 1. Parsing </h4>
|
|
<h5> The parse_tree.m package </h5>
|
|
|
|
<p>
|
|
The first part of parsing is in the parse_tree.m package,
|
|
which contains the modules listed below
|
|
(except for the library/*.m modules,
|
|
which are in the standard library).
|
|
This part produces the parse_tree.m data structure,
|
|
which is intended to match up as closely as possible
|
|
with the source code, so that it is suitable for tasks
|
|
such as pretty-printing.
|
|
|
|
<p>
|
|
|
|
<ul>
|
|
<li>
|
|
<p>
|
|
lexical analysis (library/lexer.m)
|
|
|
|
<li>
|
|
<p>
|
|
stage 1 parsing - convert strings to terms.
|
|
<p>
|
|
|
|
library/parser.m contains the code to do this, while
|
|
library/term.m and library/varset.m contain the term and varset
|
|
data structures that result, and predicates for manipulating them.
|
|
|
|
<li>
|
|
<p>
|
|
stage 2 parsing - convert terms to `items' (declarations, clauses, etc.)
|
|
<p>
|
|
The result of this stage is a parse tree
|
|
that has a close correspondence with the source code.
|
|
The parse tree data structure definition is in prog_data.m,
|
|
prog_data_event.m, prog_data_foreign.m, prog_data_pragma.m,
|
|
prog_data_used_modules.m, prog_item.m and file_kind.m,
|
|
while the code to create it is in the prog_io*.m modules:
|
|
<ul>
|
|
<li>
|
|
prog_io.m handles the top level tasks of reading in
|
|
whole Mercury source files.
|
|
<li>
|
|
prog_io_find.m locates source files containing Mercury modules.
|
|
<li>
|
|
prog_io_item.m parses in the top level parts of items,
|
|
particularly declarations.
|
|
<li>
|
|
prog_io_dcg.m parses clauses using Definite Clause Grammar notation.
|
|
<li>
|
|
prog_io_goal.m parses goals.
|
|
<li>
|
|
prog_io_vars.m parses lists of variables.
|
|
<li>
|
|
prog_io_type_name.m parses type names, while
|
|
prog_io_inst_mode_name.m parses inst and mode names.
|
|
<li>
|
|
prog_io_type_defn.m parses type definitions, while
|
|
prog_io_inst_mode_defn.m parses inst and mode definitions.
|
|
<li>
|
|
prog_io_typeclass.m parses typeclass and instance declarations.
|
|
<li>
|
|
prog_io_pragma.m parses pragma declarations.
|
|
<li>
|
|
prog_io_mutable.m parses initialize, finalize and mutable declarations.
|
|
<li>
|
|
prog_io_sym_name.m parses symbol names and specifiers.
|
|
<li>
|
|
prog_io_error.m defines the types that represents the possible outcomes
|
|
of parsing a source file.
|
|
<li>
|
|
prog_io_util.m and prog_io_iom.m define some types and predicates
|
|
needed by the other prog_io*.m modules.
|
|
</ul>
|
|
|
|
<p>
|
|
|
|
There are several modules whose collective job it is
|
|
to print (parts of) the parse tree.
|
|
<ul>
|
|
<li>
|
|
The top levels of parse trees are output by parse_tree_out.m.
|
|
This module also outputs most kinds of items.
|
|
<li>
|
|
parse_tree_out_clause.m outputs clauses and goals.
|
|
<li>
|
|
parse_tree_out_pragma.m outputs pragmas.
|
|
<li>
|
|
parse_tree_out_pred_decl.m outputs (parts of) predicate, function
|
|
and mode declarations.
|
|
<li>
|
|
parse_tree_out_inst.m outputs insts and modes.
|
|
<li>
|
|
parse_tree_out_term.m outputs variables and terms.
|
|
<li>
|
|
parse_tree_out_info.m provides a common infrastructure
|
|
for the above modules, and for mercury_to_mercury.m.
|
|
<li>
|
|
The modules prog_out.m and mercury_to_mercury.m output
|
|
the lowest level, and smallest, parts of the parse tree.
|
|
</ul>
|
|
|
|
<p>
|
|
|
|
There are several modules that provide utility predicates
|
|
that operate on (parts of) the parse tree.
|
|
<ul>
|
|
<li>
|
|
builtin_lib_types.m contains definitions about types, type constructors
|
|
and function symbols that the Mercury implementation needs to know about.
|
|
<li>
|
|
prog_item_stats.m has facilities for gathering and printing statistics
|
|
about the parse tree.
|
|
<li>
|
|
prog_util.m contains some utility predicates
|
|
for manipulating the parse tree.
|
|
<li>
|
|
prog_detism.m contains utility predicates
|
|
for manipulating determinism and determinism components.
|
|
<li>
|
|
prog_mode.m contains utility predicates
|
|
for manipulating insts and modes.
|
|
<li>
|
|
prog_type.m contains utility predicates
|
|
for manipulating types.
|
|
<li>
|
|
prog_type_subst.m contains predicates
|
|
for performing type substitutions.
|
|
<li>
|
|
prog_rename.m contains predicates
|
|
for performing variable substitutions.
|
|
<li>
|
|
prog_foreign.m contains utility predicates
|
|
for manipulating foreign code.
|
|
<li>
|
|
prog_mutable.m contains utility predicates
|
|
for manipulating mutable variables.
|
|
<li>
|
|
prog_event.m contains utility predicates for working with events.
|
|
<li>
|
|
error_util.m contains predicates
|
|
for printing nicely formatted error messages.
|
|
<li>
|
|
maybe_error.m contains types that allow the representation
|
|
of computations that can either succeed or generate such error messages.
|
|
</ul>
|
|
|
|
<li>
|
|
<p>
|
|
imports are handled at this point (modules.m)
|
|
|
|
<p>
|
|
read_module.m has code to read in modules in the form of .m,
|
|
.int, .opt etc files.
|
|
|
|
<p>
|
|
write_module_interface_files.m has the code to write out
|
|
`.int0', `.int', `.int2', and `.int3' files.
|
|
|
|
<p>
|
|
split_parse_tree_src.m splits up the parse tree of a source file
|
|
into a sequence of raw compilation units, one unit per module
|
|
contained in the source file.
|
|
|
|
<p>
|
|
comp_unit_interface.m separates the parts of a raw compilation unit
|
|
that belong in its .int file from those that don't.
|
|
|
|
<p>
|
|
modules.m figures out what interface files to read,
|
|
and also does a bunch of other semi-related things.
|
|
|
|
<p>
|
|
check_raw_comp_unit.m checks whether a compilation unit
|
|
exports anything.
|
|
|
|
<p>
|
|
generate_dep_d_files.m generates the information from which
|
|
write_deps_file.m writes out Makefile fragments.
|
|
|
|
<p>
|
|
module_imports.m contains the module_imports type and its access
|
|
predicates.
|
|
|
|
<p>
|
|
get_dependencies.m contains predicates that compute various sorts of
|
|
direct dependencies (those caused by imports) between modules.
|
|
|
|
<p>
|
|
deps_map.m and module_deps_graph.m contain data structures
|
|
for recording indirect dependencies between modules,
|
|
and the predicates for creating and using them.
|
|
|
|
<p>
|
|
file_names.m does conversions between module names and file names.
|
|
It uses java_names.m, which contains predicates for dealing with names
|
|
of things in Java.
|
|
|
|
<p>
|
|
source_file_map.m contains code to read, write and search
|
|
the mapping between module names and file names.
|
|
|
|
<p>
|
|
module_cmds.m handles the commands for manipulating interface files of
|
|
various kinds.
|
|
|
|
<p>
|
|
item_util.m contains some utility predicates dealing with items.
|
|
|
|
<li>
|
|
<p>
|
|
module qualification of types, insts and modes
|
|
<p>
|
|
module_qual.m
|
|
<br>
|
|
Adds module qualifiers to all types insts and modes,
|
|
checking that a given type, inst or mode exists and that
|
|
there is only possible match. This is done here because
|
|
it must be done before the `.int' and `.int2' interface files
|
|
are written. This also checks whether imports are really needed
|
|
in the interface.
|
|
|
|
module_qual.m does the above by coordinating the work of its four
|
|
submodules.
|
|
<dl>
|
|
<dt> module_qual.collect_mq_info.m
|
|
<dd>
|
|
collects information about what types, insts etc are defined
|
|
in which modules.
|
|
<dt> module_qual.qualify_items.m
|
|
<dd>
|
|
uses the collected information to module qualify items
|
|
and their components.
|
|
<dt> module_qual.id_set.m
|
|
<dd>
|
|
defines the data structure used by collect_mq_info and qualify_items
|
|
to do their job and communicate with each other
|
|
<dt> module_qual.qual_errors.m
|
|
<dd>
|
|
handles the errors that arise when an item refers to an entity
|
|
(type, or inst, or ...) that is either not defined anywhere,
|
|
or is defined in more than once module, and the reference
|
|
does not indicate which one is intended.
|
|
</dl>
|
|
|
|
<p>
|
|
Notes on module qualification:
|
|
<ul>
|
|
<li>
|
|
all types, typeclasses, insts and modes occurring in pred, func,
|
|
type, typeclass and mode declarations are module qualified by
|
|
module_qual.m and its submodules.
|
|
<li>
|
|
all types, insts and modes occurring in lambda expressions,
|
|
explicit type qualifications, and clause mode annotations
|
|
are module qualified in make_hlds.m.
|
|
<li>
|
|
constructors occurring in predicate and function mode declarations
|
|
are module qualified during type checking.
|
|
<li>
|
|
predicate and function calls and constructors within goals
|
|
are module qualified during mode analysis.
|
|
</ul>
|
|
|
|
<li>
|
|
<p>
|
|
expansion of equivalence types (equiv_type.m)
|
|
<p>
|
|
`with_type` and `with_inst` annotations on predicate
|
|
and function type and mode declarations are also expanded.
|
|
<p>
|
|
Expansion of equivalence types is really part of type-checking,
|
|
but is done on the item_list rather than on the HLDS because it
|
|
turned out to be much easier to implement that way.
|
|
</ul>
|
|
|
|
<p>
|
|
That is all the modules in the parse_tree.m package.
|
|
|
|
<h5> The hlds.m package </h5>
|
|
<p>
|
|
Once the stages listed above are complete, we then convert from the parse_tree
|
|
data structure to a simplified data structure, which no longer attempts
|
|
to maintain a one-to-one correspondence with the source code.
|
|
This simplified data structure is called the High Level Data Structure (HLDS),
|
|
which is defined in the hlds.m package.
|
|
|
|
<p>
|
|
The last stage of parsing is this conversion to HLDS,
|
|
which is done mostly by the following submodules
|
|
of the make_hlds module in the hlds package.
|
|
<dl>
|
|
|
|
<dt> make_hlds_passes.m
|
|
<dd>
|
|
This submodule calls the others to perform the conversion.
|
|
|
|
<dt> make_hlds_separate_items.m
|
|
<dd>
|
|
This submodule separates out the different kinds of items,
|
|
so that when make_hlds_passes.m adds one kind of item (e.g. clauses)
|
|
to the HLDS, it can rely on the fact that all items of another kind
|
|
(e.g. predicate declarations) have already been processed.
|
|
|
|
<dt> superhomogeneous.m
|
|
<dd>
|
|
Performs the conversion of unifications into superhomogeneous form.
|
|
|
|
<dt> state_var.m
|
|
<dd>
|
|
Expands away state variable syntax.
|
|
|
|
<dt> field_access.m
|
|
<dd>
|
|
Expands away field access syntax.
|
|
|
|
<dt> goal_expr_to_goal.m
|
|
<dd>
|
|
Converts clauses from parse_tree format to hlds format.
|
|
Eliminates universal quantification
|
|
(using `all [Vs] G' ===> `not (some [Vs] (not G))')
|
|
and implication (using `A => B' ===> `not(A, not B)').
|
|
|
|
<dt> add_clause.m
|
|
<dd>
|
|
Oversees the conversion of clauses from parse_tree format to hlds format.
|
|
Handles their addition to procedures,
|
|
which is nontrivial in the presence of mode-specific clauses.
|
|
|
|
<dt> add_pred.m
|
|
<dd>
|
|
Handles type and mode declarations for predicates.
|
|
|
|
<dt> add_type.m
|
|
<dd>
|
|
Handles the declarations of types.
|
|
|
|
<dt> add_mode.m
|
|
<dd>
|
|
Handles the declarations of insts and modes,
|
|
including checking for circular insts and modes.
|
|
|
|
<dt> add_special_pred.m
|
|
<dd>
|
|
Adds unify, compare, and (if needed) index and init predicates
|
|
to the HLDS as necessary.
|
|
|
|
<dt> add_solver.m
|
|
<dd>
|
|
Adds to the HLDS the casting predicates needed by solver types.
|
|
|
|
<dt> add_mutable_aux_preds.m
|
|
<dd>
|
|
Adds to the HLDS
|
|
the auxiliary predicates (init, get, set, lock, unlock) needed by mutables.
|
|
|
|
<dt> add_class.m
|
|
<dd>
|
|
Handles typeclass and instance declarations.
|
|
|
|
<dt> du_type_layout.m
|
|
<dd>
|
|
Decides how values of discriminated union types are laid out in memory.
|
|
The two main issues it handles are floats (which can be a problem on
|
|
platforms where they don't fit in words) and the packing of enums.
|
|
|
|
<dt> qual_info.m
|
|
<dd>
|
|
Handles the abstract data types used for module qualification.
|
|
|
|
<dt> make_hlds_warn.m
|
|
<dd>
|
|
Looks for constructs that merit warnings,
|
|
such as singleton variables and variables with overlapping scopes.
|
|
|
|
<dt> make_hlds_error.m
|
|
<dd>
|
|
Error messages used by more than one submodule of make_hlds.m.
|
|
|
|
<dt> add_foreign_proc.m
|
|
<dd>
|
|
Adds foreign procs (Mercury predicates defined using foreign language code)
|
|
to the HLDS.
|
|
|
|
<dt> add_foreign_enum.m
|
|
<dd>
|
|
Adds foreign enums (Mercury enum types linked to foreign language
|
|
equivalents) to the HLDS.
|
|
|
|
<dt> add_pragma_tabling.m
|
|
<dd>
|
|
Adds everything needed to implement tabling pragmas to the HLDS.
|
|
|
|
<dt> add_pragma_type_spec.m
|
|
<dd>
|
|
Adds everything needed to implement type specialization pragmas to the HLDS.
|
|
|
|
<dt> add_pragma.m
|
|
<dd>
|
|
Adds the easiest-to-implement kinds of pragmas to the HLDS,
|
|
i.e. those that don't need their own module.
|
|
|
|
</dl>
|
|
|
|
Fact table pragmas are handled by fact_table.m
|
|
(which is part of the ll_backend.m package).
|
|
That module also reads the facts from the declared file
|
|
and compiles them into a separate C file
|
|
used by the foreign_proc body of the relevant predicate.
|
|
|
|
The conversion of the item list to HLDS also involves make_tags.m,
|
|
which chooses the data representation for each discriminated union type
|
|
by assigning tags to each functor.
|
|
|
|
<p>
|
|
The HLDS data structure itself is spread over the following modules:
|
|
|
|
<ol>
|
|
<li>
|
|
hlds_args.m defines the parts of the HLDS concerned with predicate
|
|
and function argument lists.
|
|
<li>
|
|
hlds_data.m defines the parts of the HLDS concerned with
|
|
function symbols, types, insts, modes and determinisms;
|
|
<li>
|
|
hlds_goal.m defines the part of the HLDS concerned with the
|
|
structure of goals, including the annotations on goals.
|
|
<li>
|
|
hlds_clauses.m defines the part of the HLDS concerning clauses.
|
|
<li>
|
|
hlds_rtti.m defines the part of the HLDS concerning RTTI.
|
|
<li>
|
|
const_struct.m defines the part of the HLDS concerning constant structures.
|
|
<li>
|
|
hlds_pred.m defines the part of the HLDS concerning
|
|
predicates and procedures;
|
|
<li>
|
|
pred_table.m defines the tables that index predicates and functions
|
|
on various combinations of (qualified and unqualified) names and arity.
|
|
<li>
|
|
hlds_module.m defines the top-level parts of the HLDS,
|
|
including the type module_info.
|
|
<li>
|
|
status.m defines the type that record the import/export status
|
|
of entities such as types, insts, modes, and predicates.
|
|
<li>
|
|
vartypes.m defines the data structure that maps variables to their types.
|
|
</ol>
|
|
|
|
<p>
|
|
The module hlds_out.m contains predicates to dump the HLDS to a file.
|
|
These predicates print all the information the compiler has
|
|
about each part of the HLDS.
|
|
The module hlds_desc.m, by contrast contains predicates
|
|
that describe some parts of the HLDS (e.g. goals) with brief strings,
|
|
suitable for use in progress messages used for debugging.
|
|
|
|
<p>
|
|
The module hlds_defns.m contains code to print the set of definitions
|
|
in the HLDS to a file.
|
|
When dividing a module into two or more submodules,
|
|
one can use the information thus generated
|
|
to check whether the new modules include
|
|
every type, inst, mode, predicate and function definition
|
|
in the original module exactly once.
|
|
(The other sorts of definitions, e.g. typeclass definitions,
|
|
are typically so few in number that
|
|
one can keep track of them in one's head.)
|
|
|
|
<p>
|
|
The hlds.m package also contains some utility modules that contain
|
|
various library routines which are used by other modules that manipulate
|
|
the HLDS:
|
|
|
|
<dl>
|
|
<dt> mark_tail_calls.m
|
|
<dd>
|
|
Marks directly tail recursive calls as such,
|
|
and marks procedures containing directly tail recursive calls as such.
|
|
|
|
<dt> hlds_code_util.m
|
|
<dd>
|
|
Utility routines for use during HLDS generation.
|
|
|
|
<dt> goal_form.m
|
|
<dd>
|
|
Contains predicates for determining whether HLDS goals
|
|
match various criteria.
|
|
|
|
<dt> goal_util.m
|
|
<dd>
|
|
Contains various miscellaneous utility predicates for manipulating
|
|
HLDS goals, such as attaching features to goals.
|
|
|
|
<dt> make_goal.m
|
|
<dd>
|
|
Contains predicates for creating new HLDS goals.
|
|
|
|
<dt> passes_aux.m
|
|
<dd>
|
|
Contains code to write progress messages, and higher-order code
|
|
to traverse all the predicates defined in the current module
|
|
and do something with each one.
|
|
|
|
<dt> hlds_error_util.m:
|
|
<dd>
|
|
Utility routines for printing nicely formatted error messages
|
|
for symptoms involving HLDS data structures.
|
|
For symptoms involving only structures defined in prog_data,
|
|
use parse_tree.error_util.
|
|
|
|
<dt> error_msg_inst.m:
|
|
<dd>
|
|
Utility routines for printing insts and modes
|
|
in nicely formatted error messages.
|
|
|
|
<dt> code_model.m:
|
|
<dd>
|
|
Defines a type for classifying determinisms in ways useful
|
|
to the various backends, and utility predicates on that type.
|
|
|
|
<dt> arg_info.m:
|
|
<dd>
|
|
Utility routines that the various backends use to analyze
|
|
procedures' argument lists and decide on parameter passing conventions.
|
|
|
|
<dt> hhf.m:
|
|
<dd>
|
|
Facilities for translating the bodies of predicates
|
|
to hyperhomogeneous form, for constraint based mode analysis.
|
|
|
|
<dt> inst_graph.m:
|
|
<dd>
|
|
Defines the inst_graph data type, which describes the structures of insts
|
|
for constraint based mode analysis, as well as predicates
|
|
operating on that type.
|
|
|
|
<dt> from_ground_term_util.m
|
|
<dd>
|
|
Contains types and predicates for operating on
|
|
from_ground_term scopes and their contents.
|
|
</dl>
|
|
|
|
<h4> 2. Semantic analysis and error checking </h4>
|
|
|
|
<p>
|
|
This is the check_hlds.m package,
|
|
with support from the mode_robdd.m package for constraint based mode analysis.
|
|
|
|
<p>
|
|
|
|
Any pass which can report errors or warnings must be part of this stage,
|
|
so that the compiler does the right thing for options such as
|
|
`--halt-at-warn' (which turns warnings into errors) and
|
|
`--error-check-only' (which makes the compiler only compile up to this stage).
|
|
|
|
<dl>
|
|
|
|
<dt> implicit quantification
|
|
<dd>
|
|
quantification.m
|
|
handles implicit quantification and computes
|
|
the set of non-local variables for each sub-goal.
|
|
It also expands away bi-implication (unlike the expansion
|
|
of implication and universal quantification, this expansion
|
|
cannot be done until after quantification).
|
|
This module is part of the hlds.m package
|
|
rather than the check_hlds.m package,
|
|
partly because it is rerun by several passes after semantic analysis
|
|
to update nonlocal sets after changes to procedure bodies.
|
|
The first invocation of quantification may be preceded
|
|
by a pre-quantification pass (in pre_quantification.m),
|
|
which can insert implicit existential quantifiers into trace goals
|
|
to implement a scope rule about such goals
|
|
that people tend to intuitively expect.
|
|
<p>
|
|
|
|
<dt> checking typeclass instances (check_typeclass.m)
|
|
<dd>
|
|
check_typeclass.m both checks that instance declarations satisfy all
|
|
the appropriate superclass constraints
|
|
(including functional dependencies)
|
|
and performs a source-to-source transformation on the
|
|
methods from the instance declarations.
|
|
The transformed code is checked for type, mode, uniqueness, purity
|
|
and determinism correctness by the later passes, which has the effect
|
|
of checking the correctness of the instance methods themselves
|
|
(ie. that the instance methods match those expected by the typeclass
|
|
declaration).
|
|
During the transformation,
|
|
pred_ids and proc_ids are assigned to the methods for each instance.
|
|
|
|
<p>
|
|
While checking that the superclasses of a class are satisfied
|
|
by the instance declaration, a set of constraint_proofs are built up
|
|
for the superclass constraints. These are used by polymorphism.m when
|
|
generating the base_typeclass_info for the instance.
|
|
|
|
<p>
|
|
This module also checks that there are no ambiguous pred/func
|
|
declarations (that is, it checks that all type variables in constraints
|
|
are determined by type variables in arguments),
|
|
checks that there are no cycles in the typeclass hierarchy,
|
|
and checks that each abstract instance has a corresponding
|
|
typeclass instance.
|
|
<p>
|
|
|
|
<dt> check user defined insts for consistency with types
|
|
<dd>
|
|
inst_check.m checks that all user defined bound insts are consistent
|
|
with at least one type in scope
|
|
(i.e. that the set of function symbols
|
|
in the bound list for the inst are a subset of the allowed function
|
|
symbols for at least one type in scope).
|
|
|
|
<p>
|
|
The compiler generates a warning if it finds any user defined bound insts
|
|
that are not consistent with any types in scope.
|
|
<p>
|
|
|
|
<dt> pretest user defined insts
|
|
<dd>
|
|
inst_user.m performs on user defined bound insts
|
|
the tests whose results the compiler needs,
|
|
and records the results in the insts themselves.
|
|
This is faster than having the compiler perform those tests repeatedly
|
|
each time it needs the results of those tests.
|
|
|
|
<dt> improving the names of head variables
|
|
<dd>
|
|
headvar_names.m tries to replace names of the form HeadVar__n
|
|
with actual names given by the programmer.
|
|
<p>
|
|
For efficiency, this phase not a standalone pass,
|
|
but is instead invoked by the typechecker.
|
|
|
|
<dt> type checking
|
|
<dd>
|
|
<ul>
|
|
<li>
|
|
typecheck.m handles type checking, overloading resolution &
|
|
module name resolution, and almost fully qualifies all predicate
|
|
and functor names. It sets the map(var, type) field in the
|
|
pred_info. However, typecheck.m doesn't figure out the pred_id
|
|
for function calls or calls to overloaded predicates. That can't
|
|
be done in a single pass of typechecking, and so it is done
|
|
later on (in purity.m for overloaded predicate calls, and in
|
|
resolve_unify_functor.m for function calls)
|
|
<li>
|
|
type_assign.m and typecheck_info.m define
|
|
the main data structures used by typechecking.
|
|
<li>
|
|
typecheck_errors.m handles outputting of type errors.
|
|
<li>
|
|
typeclasses.m checks typeclass constraints, and
|
|
any redundant constraints that are eliminated are recorded (as
|
|
constraint_proofs) in the pred_info for future reference.
|
|
<li>
|
|
type_util.m contains utility predicates dealing with types
|
|
that are used in a variety of different places within the compiler
|
|
<li>
|
|
post_typecheck.m may also be considered to logically be a part
|
|
of typechecking, although it also prepares for mode analysis.
|
|
It contains tests for errors such as unbound type and inst variables,
|
|
unsatisfied type class constraints, and indistinguishable predicate
|
|
or function modes. These tests can't be done in the main type
|
|
checking pass, because they depend on type analysis being
|
|
already complete.
|
|
<li>
|
|
check_promise.m records each promise in the appropriate table
|
|
(the assertion table or the promise_ex table), and removes them
|
|
from further processing as predicates.
|
|
<li>
|
|
check_for_missing_type_defns.m checks for locally defined types
|
|
that have an abstract definition but no corresponding
|
|
concrete definition.
|
|
</ul>
|
|
<p>
|
|
|
|
<dt> assertions
|
|
<dd>
|
|
assertion.m (XXX in the hlds.m package)
|
|
is the abstract interface to the assertion table.
|
|
Currently all the compiler does is type check the assertions and
|
|
record for each predicate that is used in an assertion, which
|
|
assertion it is used in. The set up of the assertion table occurs
|
|
in post_typecheck.finish_assertion.
|
|
<p>
|
|
|
|
<dt> purity analysis
|
|
<dd>
|
|
purity.m is responsible for purity checking, as well as
|
|
defining the <CODE>purity</CODE> type and a few public
|
|
operations on it. It also calls post_typecheck.m to
|
|
complete the handling of predicate
|
|
overloading for cases which typecheck.m is unable to handle,
|
|
and to check for unbound type variables.
|
|
Elimination of double negation is also done here; that needs to
|
|
be done after quantification analysis and before mode analysis.
|
|
Calls to `private_builtin.unsafe_type_cast/2' are converted
|
|
into `generic_call(unsafe_cast, ...)' goals here.
|
|
<p>
|
|
|
|
<dt> implementation-defined literals
|
|
<dd>
|
|
implementation_defined_literals.m replaces unifications
|
|
of the form <CODE>Var = $name</CODE> by unifications to string
|
|
or integer constants.
|
|
<p>
|
|
|
|
<dt> polymorphism transformation
|
|
<dd>
|
|
polymorphism.m handles introduction of type_info arguments for
|
|
polymorphic predicates and introduction of typeclass_info arguments
|
|
for typeclass-constrained predicates.
|
|
This phase needs to come before mode analysis so that mode analysis
|
|
can properly reorder code involving existential types.
|
|
(It also needs to come before simplification so that simplify.m's
|
|
optimization of goals with no output variables doesn't do the
|
|
wrong thing for goals whose only output is the type_info for
|
|
an existentially quantified type parameter.)
|
|
<p>
|
|
This phase also
|
|
converts higher-order predicate terms into lambda expressions,
|
|
and copies the clauses to the proc_infos in preparation for
|
|
mode analysis.
|
|
<p>
|
|
The polymorphism.m module also exports some utility routines that
|
|
are used by other modules. These include some routines for generating
|
|
code to create type_infos, which are used by simplify.m and magic.m
|
|
when those modules introduce new calls to polymorphic procedures.
|
|
<p>
|
|
When it has finished, polymorphism.m calls clause_to_proc.m to
|
|
make duplicate copies of the clauses for each different mode of
|
|
a predicate; all later stages work on procedures, not predicates.
|
|
<p>
|
|
|
|
<dt> mode analysis
|
|
<dd>
|
|
<ul>
|
|
<li>
|
|
modes.m is the top analysis module.
|
|
It checks that procedures are mode-correct.
|
|
<li>
|
|
modecheck_goal.m does most of the work.
|
|
It handles the tasks that are common to all kinds of goals,
|
|
including annotating each goal with a delta-instmap
|
|
that specifies the changes in instantiatedness of each
|
|
variable over that goal, and does the analysis of several
|
|
kinds of goals.
|
|
<li>
|
|
modecheck_conj.m is the sub-module which analyses conjunctions
|
|
It reorders code as necessary.
|
|
<li>
|
|
modecheck_unify.m is the sub-module which analyses
|
|
unification goals.
|
|
It also module qualifies data constructors.
|
|
<li>
|
|
modecheck_call.m is the sub-module which analyses calls.
|
|
|
|
<p>
|
|
|
|
The following sub-modules are used:
|
|
<dl>
|
|
|
|
<dt> mode_info.m
|
|
<dd>
|
|
The main data structure for mode analysis.
|
|
|
|
<dt> delay_info.m
|
|
<dd>
|
|
A sub-component of the mode_info data structure used for
|
|
storing the information for scheduling: which goals are currently
|
|
delayed, what variables they are delayed on, etc.
|
|
|
|
<dt> modecheck_util.m
|
|
<dd>
|
|
Utility predicates useful during mode analysis.
|
|
|
|
<dt> instmap.m (XXX in the hlds.m package)
|
|
<dd>
|
|
Defines the instmap and instmap_delta ADTs
|
|
which store information on what instantiations
|
|
a set of variables may be bound to.
|
|
|
|
<dt> inst_match.m
|
|
<dd>
|
|
This contains the code for examining insts and
|
|
checking whether they match.
|
|
|
|
<dt> inst_util.m
|
|
<dd>
|
|
This contains the code for creating new insts from
|
|
old ones: unifying them, merging them and so on.
|
|
|
|
<dt> mode_comparison.m
|
|
<dd>
|
|
This module compares different modes of a predicate.
|
|
|
|
<dt> mode_errors.m
|
|
<dd>
|
|
This module contains all the code to
|
|
generate error messages for mode errors.
|
|
|
|
<dt> proc_requests.m
|
|
<dd>
|
|
This module contains the queue of procedures that mode analysis has
|
|
discovered a need for, but which don't yet exist. This may be
|
|
a mode other than (in,in) for the automatically generated
|
|
unify predicate for a type,
|
|
a mode other than (out,in,in) for the automatically generated
|
|
compare predicate for a type,
|
|
or a new mode for a user-defined predicate or function
|
|
whose set of modes is being inferred.
|
|
</dl>
|
|
<li>
|
|
mode_util.m contains miscellaneous useful predicates dealing
|
|
with modes (many of these are used by lots of later stages
|
|
of the compiler)
|
|
<li>
|
|
mode_debug.m contains utility code for tracing the actions
|
|
of the mode checker.
|
|
<li>
|
|
delay_partial_inst.m adds a post-processing pass on mode-correct
|
|
procedures to avoid creating intermediate, partially instantiated
|
|
data structures.
|
|
</ul>
|
|
<p>
|
|
|
|
<dt> constraint based mode analysis
|
|
<dd>
|
|
This is an experimental alternative to the usual mode analysis algorithm.
|
|
It works by building a system of boolean constraints about where
|
|
(parts of) variables can be bound, and then solving those constraints.
|
|
|
|
<ul>
|
|
<li>
|
|
mode_constraints.m is the module that finds the constraints
|
|
and adds them to the constraint store.
|
|
<li>
|
|
mode_ordering.m is the module that uses solutions of the
|
|
constraint system to find an ordering for the goals in conjunctions.
|
|
<li>
|
|
mode_constraint_robdd.m is the interface to the modules
|
|
that perform constraint solving using reduced ordered binary decision
|
|
diagrams (robdds).
|
|
<li>
|
|
We have several implementations of solvers using robdds.
|
|
Each solver is in a module named mode_robdd.X.m, and they all belong
|
|
to the top-level mode_robdd.m.
|
|
</ul>
|
|
<p>
|
|
|
|
<dt> constraint based mode analysis propagation solver
|
|
<dd>
|
|
This is a new alternative for the constraint based mode analysis algorithm.
|
|
It will perform conjunct reordering for mercury programs of a limited
|
|
syntax (it calls error if it encounters higher order code or a parallel
|
|
conjunction, or is asked to infer modes).
|
|
|
|
<ul>
|
|
<li>
|
|
prop_mode_constraints.m is the interface to the old mode_constraints.m.
|
|
It builds constraints for an SCC.
|
|
<li>
|
|
build_mode_constraints.m is the module that traverses a predicate
|
|
to build constraints for it.
|
|
<li>
|
|
abstract_mode_constraints.m describes data structures for the
|
|
constraints themselves.
|
|
<li>
|
|
ordering_mode_constraints.m solves constraints to determine
|
|
the producing and consuming goals for program variables, and
|
|
performs conjunct reordering based on the result.
|
|
<li>
|
|
mcsolver.m contains the constraint solver used by
|
|
ordering_mode_constraints.m.
|
|
</ul>
|
|
<p>
|
|
|
|
<dt> indexing and determinism analysis
|
|
<dd>
|
|
<ul>
|
|
<li>
|
|
switch_detection.m transforms into switches those disjunctions
|
|
in which several disjuncts test the same variable against different
|
|
function symbols.
|
|
<li>
|
|
cse_detection.m looks for disjunctions in which each disjunct tests
|
|
the same variable against the same function symbols, and hoists any
|
|
such unifications out of the disjunction.
|
|
If cse_detection.m modifies the code,
|
|
it will re-run mode analysis and switch detection.
|
|
<li>
|
|
det_analysis.m annotates each goal with its determinism;
|
|
it inserts cuts in the form of "some" goals wherever the determinisms
|
|
and delta instantiations of the goals involved make it necessary.
|
|
Any errors found during determinism analysis are reported by
|
|
det_report.m.
|
|
<li>
|
|
det_util.m contains utility predicates used in several modules.
|
|
</ul>
|
|
<p>
|
|
|
|
<dt> checking of unique modes (unique_modes.m)
|
|
<dd>
|
|
unique_modes.m checks that non-backtrackable unique modes were
|
|
not used in a context which might require backtracking.
|
|
Note that what unique_modes.m does is quite similar to
|
|
what modes.m does, and unique_modes calls lots of predicates
|
|
defined in modes.m to do it.
|
|
<p>
|
|
|
|
<dt> stratification checking
|
|
<dd>
|
|
The module stratify.m implements the `--warn-non-stratification' warning,
|
|
which is an optional warning that checks for loops through negation.
|
|
<p>
|
|
|
|
<dt> oisu pragma checking
|
|
<dd>
|
|
Check whether the predicates mentioned in any pragmas about
|
|
order independent state update obey the requirements placed on them
|
|
by those pragmas.
|
|
<p>
|
|
|
|
<dt> try goal expansion
|
|
<dd>
|
|
try_expand.m expands `try' goals into calls to predicates in the
|
|
`exception' module instead.
|
|
<p>
|
|
|
|
<dt> simplification (simplify.m and its submodules)
|
|
<dd>
|
|
Simplification finds and exploits opportunities for simplifying the
|
|
internal form of the program, both to optimize the code and to
|
|
massage the code into a form the code generator will accept.
|
|
It also warns the programmer about any constructs that are so simple
|
|
that they should not have been included in the program in the first
|
|
place. (That's why this pass needs to be part of semantic analysis:
|
|
because it can report warnings.)
|
|
|
|
<p>
|
|
simplify.m is a package of submodules.
|
|
|
|
<ol>
|
|
<li>
|
|
simplify_goal.m handles simplifications that involve
|
|
the interaction of a goal with its environment,
|
|
and then invokes one of the goal-type-specific submodules
|
|
for further processing.
|
|
<li>
|
|
simplify_goal_call.m handles calls (plain, generic and foreign code).
|
|
Using const_prop.m in the transform_hlds.m package,
|
|
it attempts to partially evaluate calls to builtin procedures
|
|
if the inputs are all constants.
|
|
<li>
|
|
simplify_goal_unify.m handles unifications.
|
|
Amongst other things, it converts complicated unifications
|
|
into procedure calls.
|
|
<li>
|
|
simplify_goal_conj.m handles conjunctions.
|
|
It inlines nested conjunctions, eliminates unreachable code,
|
|
and eliminates assign unification conjuncts
|
|
(replacing the assigned-to variable with the assigned-from variable
|
|
in the rest of the conjunction) if this is possible.
|
|
<li>
|
|
simplify_goal_disj.m handles disjunctions (and atomic goals).
|
|
It eliminates unnecessary disjunction wrappers,
|
|
and transforms semidet disjunctions into if-then-elses
|
|
if this possible.
|
|
<li>
|
|
simplify_goal_ite.m handles if-then-elses (and negations).
|
|
It warns about if-then-elses in which
|
|
either the then-part or the else-part is unreachable,
|
|
and about if-then-elses that should be replaced by switches.
|
|
<li>
|
|
simplify_goal_switch.m handles switches.
|
|
It eliminates switch arms that cannot fail, and switches
|
|
with no arms left.
|
|
<li>
|
|
simplify_goal_scope.m handles scope goals.
|
|
It eliminates unnecessary nested scopes,
|
|
replaces from_ground_term_construct scopes
|
|
with a single assignment unifications referencing
|
|
a constant structure in a constant structure database
|
|
(to eliminate the need for any later passes to traverse the scope),
|
|
and evaluates compile-time conditions on trace goals,
|
|
eliminating either the compile-time condition wrapper on the trace goal
|
|
(if the condition is true)
|
|
or the trace goal scope altogether
|
|
(if the condition is false).
|
|
<li>
|
|
common.m looks for (a) construction unifications
|
|
that construct a term that is the same as one that already exists,
|
|
or (b) repeated calls to a predicate with the same inputs.
|
|
It replaces both with assignment unifications.
|
|
It is invoked by the goal-type-specific submodules above.
|
|
<li>
|
|
format_call.m looks for calls to predicates such as
|
|
string.format and io.format.
|
|
It reports calls in which the types of the values to be printed
|
|
disagree with the format string,
|
|
and/or calls in which the agreement cannot be established.
|
|
It also attempts to partially evaluate the correct calls,
|
|
essentially interpreting the format string at compile time,
|
|
not runtime.
|
|
<li>
|
|
simplify_proc.m handles the top-level processing of procedures
|
|
and their bodies.
|
|
<li>
|
|
simplify_info.m defines the data structure
|
|
that is threaded through the code of the submodules above,
|
|
containing the information those submodules need.
|
|
<li>
|
|
simplify_tasks.m defines the type that identifies the tasks
|
|
that the simplification package may be asked to do.
|
|
Simplification can be invoked at several different points
|
|
in the compilation process;
|
|
different invocations need to perform different subsets
|
|
of the tasks that simplification is capable of.
|
|
</ol>
|
|
<p>
|
|
|
|
<dt> unused imports (unused_imports.m)
|
|
<dd>
|
|
unused_imports.m determines which imports of the module
|
|
are not required for the module to compile. It also identifies
|
|
which imports of a module can be moved from the interface to the
|
|
implementation.
|
|
<p>
|
|
|
|
<dt> style checks (style_checks.m)
|
|
<dd>
|
|
style_checks.m generates warnings if a predicate or function
|
|
declaration is not followed immediately by all the mode declarations
|
|
of that predicate or function, and for module bodies in which either
|
|
the exported or nonexported predicates and functions have one order
|
|
for their declarations and a different order for their definitions.
|
|
<p>
|
|
|
|
<dt> xml documentation (xml_documentation.m)
|
|
<dd>
|
|
xml_documentation.m outputs a XML representation of all the declarations
|
|
in the module. This XML representation is designed to be transformed
|
|
via XSL into more human readable documentation.
|
|
<p>
|
|
|
|
</dl>
|
|
|
|
<h4> 3. High-level transformations </h4>
|
|
|
|
<p>
|
|
This is the transform_hlds.m package.
|
|
|
|
<p>
|
|
|
|
The first pass of this stage does tabling transformations (table_gen.m).
|
|
This involves the insertion of several calls to tabling predicates
|
|
defined in mercury_builtin.m and the addition of some scaffolding structure.
|
|
Note that this pass can change the evaluation methods of some procedures to
|
|
eval_table_io, so it should come before any passes that require definitive
|
|
evaluation methods (e.g. inlining).
|
|
|
|
<p>
|
|
|
|
The next pass of this stage is a code simplification, namely
|
|
removal of lambda expressions (lambda.m):
|
|
|
|
<ul>
|
|
<li>
|
|
lambda.m converts lambda expressions into higher-order predicate terms
|
|
referring to freshly introduced separate predicates.
|
|
This pass needs to come after unique_modes.m to ensure that
|
|
the modes we give to the introduced predicates are correct.
|
|
It also needs to come after polymorphism.m since polymorphism.m
|
|
doesn't handle higher-order predicate constants.
|
|
</ul>
|
|
|
|
(Is there any good reason why lambda.m comes after table_gen.m?)
|
|
|
|
<p>
|
|
|
|
The next pass also simplifies the HLDS by expanding out the atomic goals
|
|
implementing Software Transactional Memory (stm_expand.m).
|
|
|
|
<p>
|
|
|
|
Expansion of equivalence types (equiv_type_hlds.m)
|
|
|
|
<ul>
|
|
<li>
|
|
This pass expands equivalences which are not meant to be visible
|
|
to the user of imported modules. This is necessary for the Java
|
|
and C# back-ends and in some cases for `:- pragma foreign_export'
|
|
involving foreign types on the C back-end.
|
|
|
|
<p>
|
|
|
|
It is also needed by the MLDS->C back-end, for --high-level-data,
|
|
and for cases involving abstract equivalence types which are defined
|
|
as "float".
|
|
</ul>
|
|
|
|
<p>
|
|
|
|
Exception analysis. (exception_analysis.m)
|
|
|
|
<ul>
|
|
<li>
|
|
This pass annotates each module with information about whether
|
|
the procedures in the module may throw an exception or not.
|
|
</ul>
|
|
|
|
<p>
|
|
|
|
The next pass is termination analysis.
|
|
The compiler contains <em>two</em> separate termination analysis systems,
|
|
which are based on different principles.
|
|
|
|
The modules involved in the first system are:
|
|
|
|
<ul>
|
|
<li>
|
|
termination.m is the control module. It sets the argument size and
|
|
termination properties of builtin and compiler generated procedures,
|
|
invokes term_pass1.m and term_pass2.m
|
|
and writes .trans_opt files and error messages as appropriate.
|
|
<li>
|
|
term_pass1.m analyzes the argument size properties
|
|
of user-defined procedures,
|
|
<li>
|
|
term_pass2.m analyzes the termination properties
|
|
of user-defined procedures.
|
|
<li>
|
|
term_traversal.m contains code common to the two passes.
|
|
<li>
|
|
term_errors.m defines the various kinds of termination errors
|
|
and prints the messages appropriate for each.
|
|
<li>
|
|
term_util.m defines the main types used in termination analysis
|
|
and contains utility predicates.
|
|
<li>
|
|
post_term_analysis.m contains error checking routines and optimizations
|
|
that depend upon the information obtained by termination analysis.
|
|
</ul>
|
|
|
|
The modules involved in the second system are:
|
|
|
|
<ul>
|
|
<li>
|
|
term_constr_main.m is the control module; it invokes the others as needed.
|
|
<li>
|
|
term_constr_initial.m sets up the initial state of the analysis,
|
|
based on things such as user-provided annotations.
|
|
<li>
|
|
term_constr_build.m builds an abstract representation
|
|
of the procedures to be analyzed.
|
|
<li>
|
|
term_constr_fixpoint.m uses that abstract representation
|
|
to derive information about the relationships
|
|
among the sizes of the arguments of each analyzed procedure.
|
|
<li>
|
|
term_constr_pass2.m uses this information about argument size relationships
|
|
to attempt to prove whether the analyzed procedures terminate.
|
|
<li>
|
|
term_constr_main_types.m defines the types that represent the result
|
|
of the analysis.
|
|
<li>
|
|
term_constr_data.m defines types needed during the analysis.
|
|
<li>
|
|
term_constr_errors.m generates error messages for termination problems.
|
|
</ul>
|
|
|
|
<p>
|
|
|
|
Trail usage analysis. (trailing_analysis.m)
|
|
|
|
<ul>
|
|
<li>
|
|
This pass annotates each module with information about whether
|
|
the procedures in the module modify the trail or not. This
|
|
information can be used to avoid redundant trailing operations.
|
|
</ul>
|
|
|
|
<p>
|
|
|
|
Minimal model tabling analysis. (tabling_analysis.m)
|
|
|
|
<ul>
|
|
<li>
|
|
This pass annotates each goal in a module with information about
|
|
whether the goal calls procedures that are evaluated using
|
|
minimal model tabling. This information can be used to reduce
|
|
the overhead of minimal model tabling.
|
|
|
|
</ul>
|
|
|
|
<p>
|
|
The results of these program analyses
|
|
are written out to `.trans_opt' files by intermod.m.
|
|
intermod.m is also responsible for creating `.opt' files.
|
|
Besides containing some analysis results,
|
|
`.opt' files may also contain contains clauses
|
|
for predicates (exported or local),
|
|
if these clauses are suitable for other optimizations
|
|
such as inlining or higher-order specialization.
|
|
|
|
<p>
|
|
|
|
Most of the remaining HLDS-to-HLDS transformations are optimizations:
|
|
|
|
<ul>
|
|
<li>
|
|
specialization of higher-order and polymorphic predicates where the value
|
|
of the higher-order/type_info/typeclass_info arguments are known
|
|
(higher_order.m)
|
|
|
|
<li>
|
|
attempt to introduce accumulators (accumulator.m). This optimizes
|
|
procedures whose tail consists of independent associative computations
|
|
or independent chains of commutative computations into a tail
|
|
recursive form by the introduction of accumulators. If lco is turned
|
|
on it can also transform some procedures so that only construction
|
|
unifications are after the recursive call. This pass must come before
|
|
lco, unused_args (eliminating arguments makes it hard to relate the
|
|
code back to the assertion) and inlining (can make the associative
|
|
call disappear).
|
|
<p>
|
|
This pass makes use of the goal_store.m module, which is a dictionary-like
|
|
data structure for storing HLDS goals.
|
|
|
|
<li>
|
|
inlining (i.e. unfolding) of simple procedures (inlining.m)
|
|
|
|
<li>
|
|
loop_inv.m: loop invariant hoisting. This transformation moves computations
|
|
within loops that are the same on every iteration to the outside of the
|
|
loop so that the invariant computations are only computed once.
|
|
The transformation turns a single looping predicate containing invariant
|
|
computations into two: one that computes the invariants on the first
|
|
iteration and then loops by calling the second predicate with extra
|
|
arguments for the invariant values. This pass should come after inlining,
|
|
since inlining can expose important opportunities for loop invariant
|
|
hoisting. Such opportunities might not be visible before inlining
|
|
because only *part* of the body of a called procedure is loop-invariant.
|
|
|
|
<li>
|
|
deforestation and partial evaluation (deforest.m). This optimizes
|
|
multiple traversals of data structures within a conjunction, and
|
|
avoids creating intermediate data structures. It also performs
|
|
loop unrolling where the clause used is known at compile time.
|
|
deforest.m makes use of the following sub-modules (`pd_' stands for
|
|
"partial deduction"):
|
|
|
|
<ul>
|
|
<li>
|
|
constraint.m transforms goals so that goals which can fail are
|
|
executed earlier.
|
|
<li>
|
|
pd_cost.m contains some predicates to estimate the improvement
|
|
caused by deforest.m.
|
|
<li>
|
|
pd_debug.m produces debugging output.
|
|
<li>
|
|
pd_info.m contains a state type for deforestation.
|
|
<li>
|
|
pd_term.m contains predicates to check that the deforestation
|
|
algorithm terminates.
|
|
<li>
|
|
pd_util.m contains various utility predicates.
|
|
</ul>
|
|
|
|
<li>
|
|
issue warnings about unused arguments from predicates, and create
|
|
specialized versions without them (unused_args.m);
|
|
type_infos are often unused.
|
|
|
|
<li>
|
|
delay_construct.m pushes construction unifications to the right in
|
|
semidet conjunctions, in an effort to reduce the probability that it will
|
|
need to be executed.
|
|
|
|
<li>
|
|
unneeded_code.m looks for goals whose results are either not needed
|
|
at all, or needed in some branches of computation but not others. Provided
|
|
that the goal in question satisfies some requirements (e.g. it is pure,
|
|
it cannot fail etc), it either deletes the goal or moves it to the
|
|
computation branches where its output is needed.
|
|
|
|
<li>
|
|
lco.m finds predicates whose implementations would benefit
|
|
from last call optimization modulo constructor application.
|
|
|
|
<li>
|
|
elimination of dead procedures (dead_proc_elim.m). Inlining, higher-order
|
|
specialization and the elimination of unused args can make procedures dead
|
|
even if the user doesn't, and automatically constructed unification and
|
|
comparison predicates are often dead as well.
|
|
|
|
<li>
|
|
tupling.m looks for predicates that pass around several arguments,
|
|
and modifies the code to pass around a single tuple of these arguments
|
|
instead if this looks like reducing the cost of parameter passing.
|
|
|
|
<li>
|
|
untupling.m does the opposite of tupling.m: it replaces tuple arguments
|
|
with their components. This can be useful both for finding out how much
|
|
tupling has already been done manually in the source code, and to break up
|
|
manual tupling in favor of possibly more profitable automatic tupling.
|
|
|
|
<li>
|
|
dep_par_conj.m transforms parallel conjunctions to add the wait and signal
|
|
operations required by dependent AND parallelism. To maximize the amount of
|
|
parallelism available, it tries to push the signals as early as possible
|
|
in producers and the waits as late as possible in the consumers, creating
|
|
specialized versions of predicates as needed.
|
|
|
|
<li>
|
|
parallel_to_plain_conj.m transforms parallel conjunctions to plain
|
|
conjunctions, for use in grades that do not support AND-parallelism.
|
|
|
|
<li>
|
|
granularity.m tries to ensure that programs do not generate too much
|
|
parallelism. Its goal is to minimize parallelism's overhead while still
|
|
gaining all the parallelism the machine can actually exploit.
|
|
|
|
<li>
|
|
implicit_parallelism.m is a package whose task is to introduce parallelism
|
|
into sequential code automatically. Its submodules are
|
|
<ul>
|
|
<li>
|
|
introduce_parallelism.m does the main task of the package.
|
|
<li>
|
|
push_goals_together.m performs a transformation that allows
|
|
introduce_parallelism.m to do a better job.
|
|
</ul>
|
|
|
|
<li>
|
|
float_regs.m wraps higher-order terms which use float registers
|
|
if passed in contexts where regular registers would be expected,
|
|
and vice versa.
|
|
|
|
</ul>
|
|
|
|
<p>
|
|
|
|
The module transform.m contains stuff that is supposed to be useful
|
|
for high-level optimizations (but which is not yet used).
|
|
|
|
<p>
|
|
|
|
The last three HLDS-to-HLDS transformations implement
|
|
term size profiling (size_prof.m and complexity.m) and
|
|
deep profiling (deep_profiling.m, in the ll_backend.m package).
|
|
Both passes insert into procedure bodies, among other things,
|
|
calls to procedures (some of which are impure)
|
|
that record profiling information.
|
|
|
|
<h4> 4. Intermodule analysis framework </h4>
|
|
|
|
<p>
|
|
This is the analysis.m package.
|
|
|
|
<p>
|
|
|
|
The framework can be used by a few analyses in the transform_hlds.m package.
|
|
It is documented in the analysis/README file.
|
|
|
|
<hr>
|
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
|
|
<h3> a. LLDS BACK-END </h3>
|
|
|
|
<p>
|
|
This is the ll_backend.m package.
|
|
|
|
<h4> 3a. LLDS-specific HLDS -> HLDS transformations </h4>
|
|
|
|
Before LLDS code generation, there are a few more passes which
|
|
annotate the HLDS with information used for LLDS code generation,
|
|
or perform LLDS-specific transformations on the HLDS:
|
|
|
|
<dl>
|
|
<dt>
|
|
reducing the number of variables that have to be
|
|
saved across procedure calls (saved_vars.m)
|
|
<dd>
|
|
We do this by putting the code that generates
|
|
the value of a variable just before the use of
|
|
that variable, duplicating the variable and the
|
|
code that produces it if necessary, provided
|
|
the cost of doing so is smaller than the cost
|
|
of saving and restoring the variable would be.
|
|
|
|
<dt>
|
|
transforming procedure definitions to reduce the number
|
|
of variables that need their own stack slots (stack_opt.m)
|
|
<dd>
|
|
The main algorithm in stack_opt.m figures out when
|
|
variable A can be reached from a cell pointed to by
|
|
variable B, so that storing variable B on the stack
|
|
obviates the need to store variable A on the stack as well.
|
|
This algorithm relies on an implementation of
|
|
the maximal matching algorithm in matching.m.
|
|
<dt>
|
|
migration of builtins following branched structures (follow_code.m)
|
|
<dd>
|
|
This transformation improves the results of
|
|
follow_vars.m (see below)
|
|
<dt>
|
|
simplification again (simplify.m, in the check_hlds.m package)
|
|
<dd>
|
|
We run this pass a second time in case the intervening
|
|
transformations have created new opportunities for
|
|
simplification. It needs to be run immediately
|
|
before code generation, because it enforces some
|
|
invariants that the LLDS code generator relies on.
|
|
<dt>
|
|
annotation of goals with liveness information (liveness.m)
|
|
<dd>
|
|
This records the birth and death of each variable
|
|
in the HLDS goal_info.
|
|
<dt>
|
|
allocation of stack slots
|
|
<dd>
|
|
This is done by stack_alloc.m, with the assistance of
|
|
the following modules:
|
|
|
|
<ul>
|
|
<li>
|
|
live_vars.m works out which variables need
|
|
to be saved on the stack when.
|
|
<li>
|
|
graph_colour.m (in the libs.m package) contains the algorithm
|
|
that stack_alloc.m calls to convert sets of variables
|
|
that must be saved on the stack at the same time
|
|
to an assignment of a stack slot to each such variable.
|
|
</ul>
|
|
<dt>
|
|
allocating the follow vars (follow_vars.m)
|
|
<dd>
|
|
Traverses backwards over the HLDS, annotating some
|
|
goals with information about what locations variables
|
|
will be needed in next. This allows us to generate
|
|
more efficient code by putting variables in the right
|
|
spot directly. This module is not called from
|
|
mercury_compile_llds_back_end.m; it is called from
|
|
store_alloc.m.
|
|
<dt>
|
|
allocating the store map (store_alloc.m)
|
|
<dd>
|
|
Annotates each branched goal with variable location
|
|
information so that we can generate correct code
|
|
by putting variables in the same spot at the end
|
|
of each branch.
|
|
<dt>
|
|
computing goal paths (goal_path.m in the check_hlds.m package)
|
|
<dd>
|
|
The goal path of a goal defines its position in
|
|
the procedure body. This transformation attaches
|
|
its goal path to every goal, for use by the debugger.
|
|
</dl>
|
|
|
|
<h4> 4a. Code generation. </h4>
|
|
|
|
<dl>
|
|
|
|
<dt> code generation
|
|
<dd>
|
|
Code generation converts HLDS into LLDS.
|
|
For the LLDS back-end, this is also the point at which we
|
|
insert code to handle debugging and trailing, and to do
|
|
heap reclamation on failure.
|
|
The top level code generation module is proc_gen.m,
|
|
which looks after the generation of code for procedures
|
|
(including prologues and epilogues).
|
|
The predicate for generating code for arbitrary goals is in code_gen.m,
|
|
but that module handles only sequential conjunctions; it calls
|
|
other modules to handle other kinds of goals:
|
|
|
|
<ul>
|
|
<li>
|
|
ite_gen.m (if-then-elses)
|
|
<li>
|
|
call_gen.m (predicate calls and also calls to out-of-line
|
|
unification procedures)
|
|
<li>
|
|
disj_gen.m (disjunctions)
|
|
<li>
|
|
par_conj_gen.m (parallel conjunctions)
|
|
<li>
|
|
unify_gen.m (unifications)
|
|
<li>
|
|
switch_gen.m (switches), which has sub-modules
|
|
<ul>
|
|
<li>
|
|
dense_switch.m
|
|
<li>
|
|
lookup_switch.m
|
|
<li>
|
|
string_switch.m
|
|
<li>
|
|
tag_switch.m
|
|
<li>
|
|
switch_case.m
|
|
<li>
|
|
switch_util.m -- this is in the backend_libs.m
|
|
package, since it is also used by MLDS back-end
|
|
</ul>
|
|
<li>
|
|
commit_gen.m (commits)
|
|
<li>
|
|
pragma_c_gen.m (embedded C code)
|
|
</ul>
|
|
|
|
<p>
|
|
|
|
The code generator also calls middle_rec.m to do middle recursion
|
|
optimization, which is implemented during code generation.
|
|
|
|
<p>
|
|
|
|
The code generation modules make use of
|
|
<dl>
|
|
|
|
<dt> code_info.m
|
|
<dd>
|
|
The persistent part of the code generator state.
|
|
|
|
<dt> code_loc_dep.m
|
|
<dd>
|
|
The location-dependent part of the code generator state.
|
|
|
|
<dt> var_locn.m
|
|
<dd>
|
|
This defines the var_locn type, which is a
|
|
sub-component of the code_info data structure;
|
|
it keeps track of the values and locations of variables.
|
|
It implements eager code generation.
|
|
|
|
<dt> exprn_aux.m
|
|
<dd>
|
|
Various utility predicates.
|
|
|
|
<dt> code_util.m
|
|
<dd>
|
|
Some miscellaneous preds used for code generation.
|
|
|
|
<dt> lookup_util.m
|
|
<dd>
|
|
Some miscellaneous preds used for lookup switch
|
|
(and lookup disjunction) generation.
|
|
|
|
<dt> continuation_info.m
|
|
<dd>
|
|
For accurate garbage collection, collects
|
|
information about each live value after calls,
|
|
and saves information about procedures.
|
|
|
|
<dt> trace_gen.m
|
|
<dd>
|
|
Inserts calls to the runtime debugger.
|
|
|
|
<dt>
|
|
trace_params.m (in the libs.m package, since it is considered
|
|
part of option handling)
|
|
<dd>
|
|
Holds the parameter settings controlling the handling
|
|
of execution tracing.
|
|
</dl>
|
|
|
|
<dt> code generation for `pragma export' declarations (export.m)
|
|
<dd>
|
|
This is handled separately from the other parts of code generation.
|
|
mercury_compile*.m calls `export.produce_header_file' to produce
|
|
C code fragments which declare/define the C functions which are the
|
|
interface stubs for procedures exported to C.
|
|
|
|
<dt> generation of constants for RTTI data structures
|
|
<dd>
|
|
This could also be considered a part of code generation,
|
|
but for the LLDS back-end this is currently done as part
|
|
of the output phase (see below).
|
|
|
|
</dl>
|
|
|
|
<p>
|
|
|
|
The result of code generation is the Low Level Data Structure (llds.m),
|
|
which may also contains some data structures whose types are defined in rtti.m.
|
|
The code for each procedure is generated as a tree of code fragments
|
|
which is then flattened.
|
|
|
|
<h4> 5a. Low-level optimization (LLDS). </h4>
|
|
|
|
<p>
|
|
|
|
Most of the various LLDS-to-LLDS optimizations are invoked from optimize.m.
|
|
They are:
|
|
|
|
<ul>
|
|
<li>
|
|
optimization of jumps to jumps (jumpopt.m)
|
|
<li>
|
|
elimination of duplicate code sequences within procedures (dupelim.m)
|
|
<li>
|
|
elimination of duplicate procedure bodies (dupproc.m,
|
|
invoked directly from mercury_compile_llds_back_end.m)
|
|
<li>
|
|
optimization of stack frame allocation/deallocation (frameopt.m)
|
|
<li>
|
|
filling branch delay slots (delay_slot.m)
|
|
<li>
|
|
dead code and dead label removal (labelopt.m)
|
|
<li>
|
|
peephole optimization (peephole.m)
|
|
<li>
|
|
introduction of local C variables (use_local_vars.m)
|
|
<li>
|
|
removal of redundant assignments, i.e. assignments that assign a value
|
|
that the target location already holds (reassign.m)
|
|
</ul>
|
|
|
|
In addition, stdlabel.m performs standardization of labels.
|
|
This is not an optimization itself,
|
|
but it allows other optimizations to be evaluated more easily.
|
|
|
|
<p>
|
|
|
|
The module opt_debug.m contains utility routines used for debugging
|
|
these LLDS-to-LLDS optimizations.
|
|
|
|
<p>
|
|
|
|
Several of these optimizations (frameopt and use_local_vars) also
|
|
use livemap.m, a module that finds the set of locations live at each label.
|
|
|
|
<p>
|
|
|
|
Use_local_vars numbering also introduces
|
|
references to temporary variables in extended basic blocks
|
|
in the LLDS representation of the C code.
|
|
The transformation to insert the block scopes
|
|
and declare the temporary variables is performed by wrap_blocks.m.
|
|
|
|
<p>
|
|
|
|
Depending on which optimization flags are enabled,
|
|
optimize.m may invoke many of these passes multiple times.
|
|
|
|
<p>
|
|
|
|
Some of the low-level optimization passes use basic_block.m,
|
|
which defines predicates for converting sequences of instructions to
|
|
basic block format and back, as well as opt_util.m, which contains
|
|
miscellaneous predicates for LLDS-to-LLDS optimization.
|
|
|
|
<h4> 6a. Output C code </h4>
|
|
|
|
<ul>
|
|
<li>
|
|
type_ctor_info.m
|
|
(in the backend_libs.m package, since it is shared with the MLDS back-end)
|
|
generates the type_ctor_gen_info structures that list
|
|
items of information (including unification, index and compare predicates)
|
|
associated with each declared type constructor that go into the static
|
|
type_ctor_info data structure. If the type_ctor_gen_info structure is not
|
|
eliminated as inaccessible, this module adds the corresponding
|
|
type_ctor_info structure to the RTTI data structures defined in rtti.m,
|
|
which are part of the LLDS.
|
|
|
|
<li>
|
|
base_typeclass_info.m
|
|
(in the backend_libs.m package, since it is shared with the MLDS back-end)
|
|
generates the base_typeclass_info structures that
|
|
list the methods of a class for each instance declaration.
|
|
These are added to the RTTI data structures, which are part of the LLDS.
|
|
|
|
<li>
|
|
stack_layout.m generates the stack_layout structures for
|
|
accurate garbage collection. Tables are created from the data
|
|
collected in continuation_info.m.
|
|
<p>
|
|
Stack_layout.m uses prog_rep.m to generate bytecode representations
|
|
of procedure bodies for use by the declarative debugger and the deep
|
|
profiler, and prog_rep_tables.m to generate the string tables and
|
|
type tables that these representations use.
|
|
|
|
<li>
|
|
Type_ctor_info structures and stack_layout structures both contain
|
|
pseudo_type_infos, which are type_infos with holes for type variables;
|
|
these are generated by pseudo_type_info.m
|
|
(in the backend_libs.m package, since it is shared with the MLDS back-end).
|
|
|
|
<li>
|
|
llds_common.m extracts static terms from the main body of the LLDS, and
|
|
puts them at the front. If a static term originally appeared several times,
|
|
it will now appear as a single static term with multiple references to it.
|
|
[XXX FIXME this module has now been replaced by global_data.m]
|
|
|
|
<li>
|
|
transform_llds.m is responsible for doing any source to source
|
|
transformations on the llds which are required to make the C output
|
|
acceptable to various C compilers. Currently computed gotos can have
|
|
their maximum size limited to avoid a fixed limit in lcc.
|
|
|
|
<li>
|
|
Final generation of C code is done by the llds_out package. The package
|
|
subcontracts the output of RTTI structures to rtti_out.m and of other static
|
|
compiler-generated data structures (such as those used by the debugger,
|
|
the deep profiler, and in the future by the garbage collector)
|
|
to layout_out.m.
|
|
The llds_out.m package itself consists of several modules:
|
|
llds_out_file.m for printing out LLDS modules;
|
|
llds_out_instr.m for printing out LLDS instructions;
|
|
llds_out_global.m for printing out C global variables;
|
|
llds_out_data.m for printing lvals and rvals;
|
|
llds_out_code_addr.m for printing labels and other code addresses.
|
|
llds_out_util.m defines some utility types and predicates.
|
|
</ul>
|
|
|
|
<hr>
|
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
|
|
<h3> b. MLDS BACK-END </h3>
|
|
|
|
<p>
|
|
|
|
This is the ml_backend.m package.
|
|
|
|
<p>
|
|
|
|
The original LLDS code generator generates very low-level code,
|
|
since the LLDS was designed to map easily to RISC architectures.
|
|
We have developed a new back-end that generates much higher-level
|
|
code, suitable for generating Java, high-level C, etc.
|
|
This back-end uses the Medium Level Data Structure (mlds.m) as its
|
|
intermediate representation.
|
|
|
|
<h4> 3b. pre-passes to annotate/transform the HLDS </h4>
|
|
|
|
<p>
|
|
Before code generation there is a pass which annotates the HLDS with
|
|
information used for code generation:
|
|
|
|
<ul>
|
|
<li>
|
|
mark_static_terms.m (in the hlds.m package) marks
|
|
construction unifications which can be implemented using static constants
|
|
rather than heap allocation.
|
|
</ul>
|
|
|
|
<p>
|
|
For the MLDS back-end, we've tried to keep the code generator simple.
|
|
So we prefer to do things as HLDS to HLDS transformations where possible,
|
|
rather than complicating the HLDS to MLDS code generator.
|
|
Thus we have a pass which transforms the HLDS to handle trailing:
|
|
|
|
<ul>
|
|
<li>
|
|
add_trail_ops.m inserts code to manipulate the trail,
|
|
in particular ensuring that we apply the appropriate
|
|
trail operations before each choice point, when execution
|
|
resumes after backtracking, and whenever we do a commit.
|
|
The trail operations are represented as (and implemented as)
|
|
calls to impure procedures defined in library/private_builtin.m.
|
|
<li>
|
|
add_heap_ops.m is very similar to add_trail_ops.m;
|
|
it inserts code to do heap reclamation on backtracking.
|
|
</ul>
|
|
|
|
<h4> 4b. MLDS code generation </h4>
|
|
|
|
<ul>
|
|
<li>
|
|
ml_top_gen.m is the top module of the package that converts HLDS code
|
|
to MLDS. Its main submodules are ml_proc_gen.m, which handles the
|
|
translation of predicates, and ml_code_gen.m, which handles the tasks
|
|
common to all kinds of goals, as well as the tasks specific to some
|
|
goals (conjunctions, if-then-elses, negations). For other kinds of goals,
|
|
ml_code_gen.m invokes some other submodules:
|
|
|
|
<ul>
|
|
<li>
|
|
ml_unify_gen.m
|
|
<li>
|
|
ml_closure_gen.m
|
|
<li>
|
|
ml_call_gen.m
|
|
<li>
|
|
ml_foreign_proc_gen.m
|
|
<li>
|
|
ml_commit_gen.m
|
|
<li>
|
|
ml_disj_gen.m
|
|
<li>
|
|
ml_switch_gen.m, which calls upon:
|
|
<ul>
|
|
<li>
|
|
ml_lookup_switch.m
|
|
<li>
|
|
ml_string_switch.m
|
|
<li>
|
|
ml_tag_switch.m
|
|
<li>
|
|
ml_simplify_switch.m
|
|
<li>
|
|
switch_util.m (in the backend_libs.m package,
|
|
since it is also used by LLDS back-end)
|
|
</ul>
|
|
</ul>
|
|
|
|
The main data structure used by the MLDS code generator is defined
|
|
in ml_gen_info.m, while global data structures (those created at
|
|
module scope) are handled in ml_global_data.m.
|
|
The module ml_accurate_gc.m handles provisions for accurate garbage
|
|
collection, while the modules ml_args_util.m, ml_code_util.m,
|
|
ml_target_util.m and ml_util.m provide some general utility routines.
|
|
|
|
<li>
|
|
ml_type_gen.m converts HLDS types to MLDS.
|
|
|
|
<li>
|
|
type_ctor_info.m and base_typeclass_info.m generate
|
|
the RTTI data structures defined in rtti.m and pseudo_type_info.m
|
|
(those four modules are in the backend_libs.m package, since they
|
|
are shared with the LLDS back-end)
|
|
and then rtti_to_mlds.m converts these to MLDS.
|
|
</ul>
|
|
|
|
<h4> 5b. MLDS transformations </h4>
|
|
|
|
<ul>
|
|
<li>
|
|
ml_tailcall.m annotates the MLDS with information about tailcalls.
|
|
It also has a pass to implement the `--warn-non-tail-recursion' option.
|
|
<li>
|
|
ml_optimize.m does MLDS->MLDS optimizations
|
|
<li>
|
|
ml_elim_nested.m does two MLDS transformations that happen
|
|
to have a lot in common: (1) eliminating nested functions
|
|
and (2) adding code to handle accurate garbage collection.
|
|
<li>
|
|
ml_rename_class.m does what its name suggests: renames classes in the MLDS.
|
|
It is used by mlds_to_java.m to replace long class names with shorter ones.
|
|
</ul>
|
|
|
|
<h4> 6b. MLDS output </h4>
|
|
|
|
<p>
|
|
There are currently three backends that generate code from MLDS:
|
|
one generates C/C++ code,
|
|
one generates Java,
|
|
and one generates C#.
|
|
|
|
<ul>
|
|
<li>
|
|
mlds_to_c.m converts MLDS to C/C++ code.
|
|
</ul>
|
|
|
|
<p>
|
|
|
|
<ul>
|
|
<li>
|
|
mlds_to_java.m converts MLDS to Java and writes it to a .java file.
|
|
</ul>
|
|
|
|
After the Java code has been emitted, a Java compiler (normally javac)
|
|
is invoked to turn the .java file into a .class file containing Java bytecodes.
|
|
|
|
<p>
|
|
|
|
<ul>
|
|
<li>
|
|
mlds_to_cs.m converts MLDS to C# code.
|
|
</ul>
|
|
|
|
After the C# code has been emitted, a C# compiler is invoked to turn the .cs
|
|
file into a .dll or .exe.
|
|
|
|
The mlds_to_target_util.m module contains types, functions and predicates
|
|
that are needed by more than one of these MLDS backends.
|
|
|
|
<hr>
|
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
|
|
<h3> c. BYTECODE BACK-END </h3>
|
|
|
|
<p>
|
|
This is the bytecode_backend.m package.
|
|
|
|
<p>
|
|
|
|
The Mercury compiler can translate Mercury programs into bytecode for
|
|
interpretation by a bytecode interpreter. The intent of this is to
|
|
achieve faster turn-around time during development. However, the
|
|
bytecode interpreter has not yet been written.
|
|
|
|
<ul>
|
|
<li>
|
|
bytecode.m defines the internal representation of bytecodes, and contains
|
|
the predicates to emit them in two forms. The raw bytecode form is emitted
|
|
into <filename>.bytecode for interpretation, while a human-readable
|
|
form is emitted into <filename>.bytedebug for visual inspection.
|
|
|
|
<li>
|
|
bytecode_gen.m contains the predicates that translate HLDS into bytecode.
|
|
|
|
<li>
|
|
bytecode_data.m contains the predicates that translate ints, strings
|
|
and floats into bytecode.
|
|
</ul>
|
|
|
|
<hr>
|
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
|
|
<h3> d. ERLANG BACK-END </h3>
|
|
|
|
<p>
|
|
This is the erl_backend.m package.
|
|
|
|
<p>
|
|
|
|
The Mercury compiler can translate Mercury programs into Erlang.
|
|
The intent of this is to take advantage of the features of the
|
|
Erlang implementation (concurrency, fault tolerance, etc.)
|
|
However, the backend is still incomplete.
|
|
This back-end uses the Erlang Data Structure (elds.m) as its
|
|
intermediate representation.
|
|
|
|
<h4> 4d. ELDS code generation </h4>
|
|
|
|
<ul>
|
|
<li>
|
|
erl_code_gen.m converts HLDS code to ELDS.
|
|
The following sub-modules are used to handle different constructs:
|
|
<ul>
|
|
<li>
|
|
erl_unify_gen.m
|
|
<li>
|
|
erl_call_gen.m
|
|
</ul>
|
|
The module erl_code_util.m provides utility routines
|
|
for ELDS code generation.
|
|
<li>
|
|
erl_rtti.m converts RTTI data structures defined in rtti.m into
|
|
ELDS functions which return the same information when called.
|
|
</ul>
|
|
|
|
<h4> 6d. ELDS output </h4>
|
|
|
|
<ul>
|
|
<li>
|
|
elds_to_erlang.m converts ELDS to Erlang code.
|
|
</ul>
|
|
|
|
<hr>
|
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
|
|
<h3> SMART RECOMPILATION </h3>
|
|
|
|
<p>
|
|
This is the recompilation.m package.
|
|
|
|
<p>
|
|
|
|
The Mercury compiler can record program dependency information
|
|
to avoid unnecessary recompilations when an imported module's
|
|
interface changes in a way which does not invalidate previously
|
|
compiled code.
|
|
|
|
<ul>
|
|
<li>
|
|
recompilation.m contains types used by the other smart
|
|
recompilation modules.
|
|
|
|
<li>
|
|
recompilation_version.m generates version numbers for program items
|
|
in interface files.
|
|
|
|
<li>
|
|
recompilation_usage.m works out which program items were used
|
|
during a compilation.
|
|
|
|
<li>
|
|
recompilation_check.m is called before recompiling a module.
|
|
It uses the information written by recompilation_version.m and
|
|
recompilation_usage.m to work out whether the recompilation is
|
|
actually needed.
|
|
</ul>
|
|
|
|
<hr>
|
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
|
|
<h3> MISCELLANEOUS </h3>
|
|
|
|
The modules special_pred.m (in the hlds.m package) and unify_proc.m
|
|
(in the check_hlds.m package) contain stuff for handling the special
|
|
compiler-generated predicates which are generated for
|
|
each type: unify/2, compare/3, and index/1 (used in the
|
|
implementation of compare/3).
|
|
|
|
<p>
|
|
This module is part of the transform_hlds.m package.
|
|
|
|
<dl>
|
|
|
|
<dt> dependency_graph.m:
|
|
<dd>
|
|
This contains predicates to compute the call graph for a module,
|
|
and to print it out to a file.
|
|
(The call graph file is used by the profiler.)
|
|
The call graph may eventually also be used by det_analysis.m,
|
|
inlining.m, and other parts of the compiler which could benefit
|
|
from traversing the predicates in a module in a bottom-up or
|
|
top-down fashion with respect to the call graph.
|
|
|
|
</dl>
|
|
|
|
<p>
|
|
The following modules are part of the backend_libs.m package.
|
|
|
|
<dl>
|
|
<dt> arg_pack:
|
|
<dd>
|
|
This module defines utility routines to do with argument
|
|
packing.
|
|
|
|
<dt> builtin_ops:
|
|
<dd>
|
|
This module defines the types unary_op and binary_op
|
|
which are used by several of the different back-ends:
|
|
bytecode.m, llds.m, and mlds.m.
|
|
|
|
<dt> c_util:
|
|
<dd>
|
|
This module defines utility routines useful for generating C code.
|
|
It is used by both llds_out.m and mlds_to_c.m.
|
|
|
|
<dt> name_mangle:
|
|
<dd>
|
|
This module defines utility routines useful for mangling
|
|
names to forms acceptable as identifiers in target languages.
|
|
|
|
<dt> compile_target_code.m
|
|
<dd>
|
|
Invoke C, C#, Java, etc. compilers and linkers to compile
|
|
and link the generated code.
|
|
|
|
<dt> string_encoding.m:
|
|
<dd>
|
|
This module defines utility routines to do with string encodings.
|
|
|
|
</dl>
|
|
|
|
<p>
|
|
The following modules are part of the libs.m package.
|
|
|
|
<dl>
|
|
|
|
<dt> file_util.m:
|
|
<dd>
|
|
Predicates to deal with files, such as searching for a file
|
|
in a list of directories.
|
|
|
|
<dt> process_util.m:
|
|
<dd>
|
|
Predicates to deal with process creation and signal handling.
|
|
This module is mainly used by make.m and its sub-modules.
|
|
|
|
<dt> timestamp.m
|
|
<dd>
|
|
Contains an ADT representing timestamps used by smart
|
|
recompilation and `mmc --make'.
|
|
|
|
<dt> graph_color.m
|
|
<dd>
|
|
Graph colouring.
|
|
<br>
|
|
This is used by the LLDS back-end for register allocation
|
|
|
|
<dt> int_emu.m
|
|
<dd>
|
|
Emulate `int' operations for a given number of bits per int.
|
|
|
|
<dt> lp.m
|
|
<dd>
|
|
Implements the linear programming algorithm for optimizing
|
|
a set of linear constraints on floats
|
|
with respect to a linear cost function.
|
|
This is used by the first termination analyser,
|
|
whose top level is in termination.m.
|
|
|
|
<dt> lp_rational.m
|
|
<dd>
|
|
Implements the linear programming algorithm for optimizing
|
|
a set of linear constraints on rational numbers
|
|
with respect to a linear cost function.
|
|
This is used by the second, convex-constraint-based
|
|
termination analyser,
|
|
whose top level is in term_constr_main.m.
|
|
|
|
<dt> polyhedron.m
|
|
<dd>
|
|
Implements operations on convex polyhedra.
|
|
This is used by the second, convex-constraint-based
|
|
termination analyser,
|
|
whose top level is in term_constr_main.m.
|
|
|
|
<dt> rat.m
|
|
<dd>
|
|
Implements rational numbers.
|
|
|
|
<dt> compiler_util.m:
|
|
<dd>
|
|
Generic utility predicates, mainly for error handling.
|
|
|
|
<dt> mmakefiles.m:
|
|
<dd>
|
|
A representation for mmakefiles and mmakefile fragments,
|
|
and predicates for printing them.
|
|
</dl>
|
|
|
|
<hr>
|
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
|
|
<h3> CURRENTLY UNDOCUMENTED </h3>
|
|
|
|
<ul>
|
|
<li>
|
|
mmc_analysis.m
|
|
</ul>
|
|
|
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
|
|
<h3> CURRENTLY USELESS </h3>
|
|
|
|
<dl>
|
|
|
|
<dt> atsort.m (in the libs.m package)
|
|
<dd>
|
|
Approximate topological sort.
|
|
This was once used for traversing the call graph,
|
|
but nowadays we use relation.atsort from library/relation.m.
|
|
|
|
</dl>
|
|
|
|
<hr>
|
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
|
|
</body>
|
|
</html>
|