Files
mercury/compiler/structure_reuse.direct.m
Zoltan Somogyi a00596c283 The file modules.m contains lots of different kinds of functionality.
Estimated hours taken: 16
Branches: main

The file modules.m contains lots of different kinds of functionality.
While much of it belongs together, much of it does not. This diff moves
most of the functionality that does not belong with the rest to several
new modules:

	libs.file_util
	parse_tree.deps_map
	parse_tree.file_names
	parse_tree.module_cmds
	parse_tree.module_imports
	parse_tree.read_module
	parse_tree.write_deps_file

To make them coherent, move some predicates from hlds.passes_aux,
parse_tree.prog_io and parse_tree.prog_out to the new modules, making them
more accessible, reducing the required access from the hlds package to
parse_tree, or from the parse_tree package to libs.

In the same spirit, this diff also moves some simple predicates and functions
dealing with sym_names from prog_util.m to mdbcomp/prim_data.m. This allows
several modules to avoid depending on parse_tree.prog_util.

Rename some of the moved predicates and function symbols where this avoids
ambiguity. (There were several that differed from other predicates or function
symbols only in arity.)

Replace several uses of bools with purpose-specific types. This makes some
of the code significantly easier to read.

This diff moves modules.m from being by far the largest module, to being
only the seventh largest, from 8900+ lines to just 4200+. It also reduces
the number of modules that import parse_tree.modules considerably; most
modules that imported it now import only one or two of the new modules instead.

Despite the size of the diff, there should be no algorithmic changes.

compiler/modules.m:
compiler/passes_aux.m:
compiler/prog_io.m:
compiler/prog_out.m:
	Delete the moved functionality.

compiler/file_util.m:
	New module in the libs package. Its predicates search for files
	and do simple error or progress reporting.

compiler/file_names.m:
	New module in the parse_tree package. It contains predicates for
	converting module names to file names.

compiler/module_cmds.m:
	New module in the parse_tree package. Its predicates handle the
	commands for manipulating interface files of various kinds.

compiler/module_import.m:
	New module in the parse_tree package. It contains the module_imports
	type and its access predicates, and the predicates that compute
	various sorts of direct dependencies (those caused by imports)
	between modules.

compiler/deps_map.m:
	New module in the parse_tree package. It contains the data structure
	for recording indirect dependencies between modules, and the predicates
	for creating it.

compiler/read_module.m:
	New module in the parse_tree package. Its job is reading in modules,
	both human-written and machine-written (such as interface and
	optimization files).

compiler/write_deps_file.m:
	New module in the parse_tree package. Its job is writing out
	makefile fragments.

compiler/libs.m:
compiler/parse_tree.m:
	Include the new modules.

compiler/notes/compiler_design.m:
	Document the new modules.

mdbcomp/prim_data.m:
compiler/prog_util.m:
	Move the predicates that operate on nothing but sym_names from
	prog_util to prim_data.

	Move get_ancestors from modules to prim_data.

compiler/prog_item.m:
	Move stuff that looks for foreign code in a list of items here from
	modules.m.

compiler/source_file_map.m:
	Note why this module needs to be in the parse_tree package.

compiler/add_pred.m:
compiler/add_special_pred.m:
compiler/analysis.file.m:
compiler/analysis.m:
compiler/assertion.m:
compiler/check_typeclass.m:
compiler/compile_target_code.m:
compiler/cse_detection.m:
compiler/det_analysis.m:
compiler/elds_to_erlang.m:
compiler/exception_analysis.m:
compiler/export.m:
compiler/fact_table.m:
compiler/higher_order.m:
compiler/hlds_module.m:
compiler/hlds_pred.m:
compiler/intermod.m:
compiler/llds_out.m:
compiler/make.dependencies.m:
compiler/make.m:
compiler/make.module_dep_file.m:
compiler/make.module_target.m:
compiler/make.program_target.m:
compiler/make.util.m:
compiler/make_hlds_passes.m:
compiler/maybe_mlds_to_gcc.pp:
compiler/mercury_compile.m:
compiler/mlds.m:
compiler/mlds_to_c.m:
compiler/mlds_to_gcc.m:
compiler/mlds_to_ilasm.m:
compiler/mlds_to_java.m:
compiler/mmc_analysis.m:
compiler/mode_constraints.m:
compiler/mode_debug.m:
compiler/modes.m:
compiler/module_qual.m:
compiler/optimize.m:
compiler/passes_aux.m:
compiler/proc_gen.m:
compiler/prog_foreign.m:
compiler/prog_io.m:
compiler/prog_io_util.m:
compiler/prog_mutable.m:
compiler/prog_out.m:
compiler/pseudo_type_info.m:
compiler/purity.m:
compiler/recompilation.check.m:
compiler/recompilation.usage.m:
compiler/simplify.m:
compiler/structure_reuse.analysis.m:
compiler/structure_reuse.direct.detect_garbage.m:
compiler/structure_reuse.direct.m:
compiler/structure_sharing.analysis.m:
compiler/tabling_analysis.m:
compiler/term_constr_main.m:
compiler/termination.m:
compiler/trailing_analysis.m:
compiler/trans_opt.m:
compiler/type_util.m:
compiler/typecheck.m:
compiler/typecheck_info.m:
compiler/unify_proc.m:
compiler/unused_args.m:
compiler/unused_imports.m:
compiler/xml_documentation.m:
	Minor changes to conform to the changes above.
2008-07-21 03:10:29 +00:00

334 lines
12 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 2006-2008 The University of Melbourne.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%-----------------------------------------------------------------------------%
%
% File: structure_reuse.direct.m.
% Main authors: nancy.
%
% This module defines procedures and types related to the detection of so
% called "direct reuses" within the CTGC system. A direct reuse is a
% combination of the location of a deconstruction unification (where a
% datastructure may become garbage under certain conditions) and a set of
% locations of construction unifications where the garbage datastructure can
% be reused locally.
%
% Direct reuse analysis requires two steps:
% - Detecting where datastructures may become garbage.
% - Finding where these garbage datastructures can be reused.
%
%-----------------------------------------------------------------------------%
:- module transform_hlds.ctgc.structure_reuse.direct.
:- interface.
:- import_module hlds.hlds_module.
:- import_module hlds.hlds_pred.
:- import_module transform_hlds.ctgc.structure_reuse.domain.
:- import_module transform_hlds.ctgc.structure_sharing.domain.
:- import_module io.
:- import_module list.
%-----------------------------------------------------------------------------%
% The first pass, where we process all procedures defined in the module.
%
:- pred direct_reuse_pass(sharing_as_table::in, module_info::in,
module_info::out, reuse_as_table::in, reuse_as_table::out,
io::di, io::uo) is det.
% Subsequent passes, where we process only the listed procedures.
%
:- pred direct_reuse_process_specific_procs(sharing_as_table::in,
list(pred_proc_id)::in, module_info::in, module_info::out,
reuse_as_table::in, reuse_as_table::out, io::di, io::uo) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module analysis.
:- import_module hlds.passes_aux.
:- import_module libs.file_util.
:- import_module libs.globals.
:- import_module libs.options.
:- import_module parse_tree.error_util.
:- import_module transform_hlds.ctgc.structure_reuse.direct.choose_reuse.
:- import_module transform_hlds.ctgc.structure_reuse.direct.detect_garbage.
:- import_module transform_hlds.ctgc.util.
:- import_module transform_hlds.smm_common.
:- import_module bool.
:- import_module map.
:- import_module svmap.
:- include_module transform_hlds.ctgc.structure_reuse.direct.detect_garbage.
:- include_module transform_hlds.ctgc.structure_reuse.direct.choose_reuse.
%-----------------------------------------------------------------------------%
% The strategy for determining the reuse possibilities, i.e., either
% reuse is only allowed between terms that have exactly the same cons_id,
% or reuse is also allowed between terms that have different cons_id, yet
% where the difference in arity is not bigger than a given threshold.
%
:- type reuse_strategy
---> same_cons_id
; within_n_cells_difference(int).
% Determine the strategy that was set by the user.
%
:- pred get_strategy(reuse_strategy::out, module_info::in, module_info::out,
io::di, io::uo) is det.
get_strategy(Strategy, !ModuleInfo, !IO):-
io_lookup_string_option(structure_reuse_constraint, ConstraintStr, !IO),
(
ConstraintStr = "same_cons_id"
->
Strategy = same_cons_id
;
ConstraintStr = "within_n_cells_difference"
->
io_lookup_int_option(structure_reuse_constraint_arg, NCells, !IO),
Strategy = within_n_cells_difference(NCells)
;
Strategy = same_cons_id,
Pieces = [words("error: Invalid argument to "),
words("`--structure-reuse-constraint.'")],
write_error_pieces_plain(Pieces, !IO),
module_info_incr_errors(!ModuleInfo)
).
direct_reuse_pass(SharingTable, !ModuleInfo, !ReuseTable, !IO):-
% Determine the reuse strategy:
get_strategy(Strategy, !ModuleInfo, !IO),
% Gather the pred-ids of the preds that need to be analysed.
module_info_predids(AllPredIds, !ModuleInfo),
list.filter(pred_requires_analysis(!.ModuleInfo), AllPredIds,
ToBeAnalysedPredIds),
% Analyse and annotate each of the predicates.
list.foldl3(direct_reuse_process_pred(Strategy, SharingTable),
ToBeAnalysedPredIds, !ModuleInfo, !ReuseTable, !IO).
:- pred direct_reuse_process_pred(reuse_strategy::in, sharing_as_table::in,
pred_id::in, module_info::in, module_info::out, reuse_as_table::in,
reuse_as_table::out, io::di, io::uo) is det.
direct_reuse_process_pred(Strategy, SharingTable, PredId, !ModuleInfo,
!ReuseTable, !IO):-
module_info_pred_info(!.ModuleInfo, PredId, PredInfo0),
(
pred_info_get_origin(PredInfo0, Origin),
Origin = origin_special_pred(_)
->
% We can't analyse compiler generated special predicates.
true
;
pred_info_get_import_status(PredInfo0, status_external(_))
->
% We can't analyse `:- external' predicates but add an extry to the
% reuse table so something will be written out to optimisation
% interface files.
list.foldl(
set_external_pred_reuse_as(PredId, reuse_as_init, optimal),
pred_info_procids(PredInfo0), !ReuseTable)
;
ProcIds = pred_info_non_imported_procids(PredInfo0),
list.foldl3(direct_reuse_process_proc(Strategy, SharingTable, PredId),
ProcIds, !ModuleInfo, !ReuseTable, !IO)
).
:- pred set_external_pred_reuse_as(pred_id::in, reuse_as::in,
analysis_status::in, proc_id::in, reuse_as_table::in, reuse_as_table::out)
is det.
set_external_pred_reuse_as(PredId, ReuseAs, Status, ProcId, !ReuseTable) :-
reuse_as_table_set(proc(PredId, ProcId),
reuse_as_and_status(ReuseAs, Status), !ReuseTable).
direct_reuse_process_specific_procs(SharingTable, PPIds,
!ModuleInfo, !ReuseTable, !IO) :-
get_strategy(Strategy, !ModuleInfo, !IO),
list.foldl3(direct_reuse_process_ppid(Strategy, SharingTable),
PPIds, !ModuleInfo, !ReuseTable, !IO).
:- pred direct_reuse_process_ppid(reuse_strategy::in, sharing_as_table::in,
pred_proc_id::in, module_info::in, module_info::out,
reuse_as_table::in, reuse_as_table::out, io::di, io::uo) is det.
direct_reuse_process_ppid(Strategy, SharingTable, proc(PredId, ProcId),
!ModuleInfo, !ReuseTable, !IO) :-
direct_reuse_process_proc(Strategy, SharingTable, PredId, ProcId,
!ModuleInfo, !ReuseTable, !IO).
% Process one individual procedure.
%
:- pred direct_reuse_process_proc(reuse_strategy::in, sharing_as_table::in,
pred_id::in, proc_id::in, module_info::in, module_info::out,
reuse_as_table::in, reuse_as_table::out, io::di, io::uo) is det.
direct_reuse_process_proc(Strategy, SharingTable, PredId, ProcId,
!ModuleInfo, !ReuseTable, !IO) :-
module_info_preds(!.ModuleInfo, Preds0),
map.lookup(Preds0, PredId, Pred0),
pred_info_get_procedures(Pred0, Procs0),
map.lookup(Procs0, ProcId, Proc0),
direct_reuse_process_proc_2(Strategy, SharingTable, PredId, ProcId,
!.ModuleInfo, Pred0, Proc0, Proc, ReuseAs, !IO),
% XXX is this right?
Status = optimal,
reuse_as_table_set(proc(PredId, ProcId),
reuse_as_and_status(ReuseAs, Status), !ReuseTable),
map.det_update(Procs0, ProcId, Proc, Procs),
pred_info_set_procedures(Procs, Pred0, Pred),
map.det_update(Preds0, PredId, Pred, Preds),
module_info_set_preds(Preds, !ModuleInfo).
:- pred direct_reuse_process_proc_2(reuse_strategy::in,
sharing_as_table::in, pred_id::in, proc_id::in, module_info::in,
pred_info::in, proc_info::in, proc_info::out, reuse_as::out,
io::di, io::uo) is det.
direct_reuse_process_proc_2(Strategy, SharingTable, PredId, ProcId,
ModuleInfo, PredInfo, !ProcInfo, ReuseAs, !IO):-
io_lookup_bool_option(very_verbose, VeryVerbose, !IO),
write_proc_progress_message("% Direct reuse analysis of ",
PredId, ProcId, ModuleInfo, !IO),
proc_info_get_goal(!.ProcInfo, Goal0),
% Determine the deconstructions in which data may potentially become
% garbage.
%
determine_dead_deconstructions(ModuleInfo, PredInfo, !.ProcInfo,
SharingTable, Goal0, DeadCellTable),
dead_cell_table_maybe_dump(VeryVerbose, DeadCellTable, !IO),
% Determine how the detected dead datastructures can be reused.
% This annotates the goal with potential reuses.
%
determine_reuse(Strategy, ModuleInfo, !.ProcInfo, DeadCellTable,
Goal0, Goal, ReuseAs, !IO),
proc_info_set_goal(Goal, !ProcInfo),
maybe_write_string(VeryVerbose, "% reuse analysis done.\n", !IO).
%-----------------------------------------------------------------------------%
% We use the type dead_cell_table to collect all deconstructions that possibly
% leave garbage behind.
%
%
% A dead_cell_table maps program points onto reuse conditions.
%
:- type dead_cell_table == map(program_point, reuse_condition).
% Initialise a dead_cell_table.
%
:- func dead_cell_table_init = dead_cell_table.
% Check whether the table is empty.
%
:- pred dead_cell_table_is_empty(dead_cell_table::in) is semidet.
% Succeeds if the given program point is listed in the table. Return
% the associated reuse_condition.
%
:- func dead_cell_table_search(program_point, dead_cell_table)
= reuse_condition is semidet.
% Add a program point and its associated reuse_condition to the table.
%
:- pred dead_cell_table_set(program_point::in, reuse_condition::in,
dead_cell_table::in, dead_cell_table::out) is det.
% Remove a program point from the table.
%
:- pred dead_cell_table_remove(program_point::in,
dead_cell_table::in, dead_cell_table::out) is det.
% Remove all program points from the table for which the reuse_conditions
% are "conditional".
%
:- pred dead_cell_table_remove_conditionals(dead_cell_table::in,
dead_cell_table::out) is det.
% Dump the contents of the table.
%
:- pred dead_cell_table_maybe_dump(bool::in, dead_cell_table::in,
io::di, io::uo) is det.
dead_cell_table_init = map.init.
dead_cell_table_is_empty(Table) :-
map.is_empty(Table).
dead_cell_table_search(PP, Table) = Table ^ elem(PP).
dead_cell_table_set(PP, RC, !Table) :-
svmap.set(PP, RC, !Table).
dead_cell_table_remove(PP, !Table) :-
svmap.det_remove(PP, _, !Table).
dead_cell_table_remove_conditionals(!Table) :-
map.foldl(dead_cell_table_add_unconditional, !.Table,
dead_cell_table_init, !:Table).
:- pred dead_cell_table_add_unconditional(program_point::in,
reuse_condition::in, dead_cell_table::in, dead_cell_table::out) is det.
dead_cell_table_add_unconditional(PP, C, !Table) :-
(
reuse_condition_is_conditional(C)
->
true
;
dead_cell_table_set(PP, C, !Table)
).
dead_cell_table_maybe_dump(MaybeDump, Table, !IO) :-
(
MaybeDump = no
;
MaybeDump = yes,
io.write_string("\t\t|--------|\n", !IO),
map.foldl(dead_cell_entry_dump, Table, !IO),
io.write_string("\t\t|--------|\n", !IO)
).
:- pred dead_cell_entry_dump(program_point::in, reuse_condition::in,
io::di, io::uo) is det.
dead_cell_entry_dump(PP, Cond, !IO) :-
(
reuse_condition_is_conditional(Cond)
->
io.write_string("\t\t| cond |\t", !IO)
;
io.write_string("\t\t| always |\t", !IO)
),
dump_program_point(PP, !IO),
io.write_string("\n", !IO).
%-----------------------------------------------------------------------------%
:- func this_file = string.
this_file = "structure_sharing.direct.m".
%-----------------------------------------------------------------------------%
:- end_module transform_hlds.ctgc.structure_reuse.direct.
%-----------------------------------------------------------------------------%