[m-rev.] for review: more work on intermodule analysis

Peter Wang wangp at students.cs.mu.OZ.AU
Wed Feb 1 17:03:35 AEDT 2006


Estimated hours taken: 20
Branches: main

This patch mainly adds the ability to perform intermodule analysis of modules
as a separate step from compiling.  It makes a start on automatic reanalysis of
modules if their .analysis files become invalid or suboptimal.

analysis/analysis.file.m:
analysis/analysis.m:
	Add a predicate `read_module_overall_status' to read just the overall
	status of an analysis file.

	Fix a bug where analysis results were being discarded (upon reading) if
	the module's overall status was `invalid'.  We can't do that as then we
	wouldn't know which results changed after reanalysis.

	Don't write out `.analysis' and `.imdg' files which would contain no
	information.

	Touch a `FOO.analysis_date' file after module `FOO' is analysed.
	This is needed to indicate the time at which `FOO' was last analysed,
	as `FOO.analysis' can be modified at other times.

	Add a mutable boolean variable `debug_analysis' that can be set
	to enable debugging messages for the analysis framework.

compiler/handle_options.m:
compiler/options.m:
	Add new compiler options `--make-analysis-registry',
	`--debug-intermodule-analysis' and `--max-reanalysis-passes'.

compiler/make.dependencies.m:
	Add `.analysis' files as dependencies of compiled code files if
	`--intermodule-analysis' is used.

compiler/make.m:
compiler/make.module_target.m:
compiler/make.program_target.m:
compiler/make.util.m:
	Add a `FOO.analyse' pseudo-target to `mmc --make'.  This produces all
	the `.analysis' files needed to compile the top-level module `FOO',
	reanalysing modules until none of the `.analysis' files are invalid.
	The `--max-reanalysis-passes' option can also be used to force
	`suboptimal' modules to be reanalysed a number of times.

	Perform an analysis pass when building executables or libraries to make
	sure that compilation does not proceed with invalid analysis files.

	Treat `.analysis' files specially when checking whether they are out of
	date.  Analysis files require looking at their contents to determine
	whether they are invalid (in which case they are out of date), or valid
	(in which case we look at the timestamp of the corresponding
	`.analysis_date' file).

compiler/mercury_compile.m:
	Make `.analysis' be written out only when `--make-analysis-registry'
	is used, like `--make-transitive-optimization-interface'.
	`mmc --make' runs the compiler the `--make-analysis-registry'
	option as appropriate.

compiler/exception_analysis.m:
compiler/trailing_analysis.m:
compiler/unused_args.m:
	Only record intermodule dependencies and analysis results when
	`--make-analysis-registry' is enabled, not when
	`--intermodule-analysis' is enabled.

doc/user_guide.texi:
	Document `--debug-intermodule-analysis' and `--max-reanalysis-passes'.


Index: analysis/analysis.file.m
===================================================================
RCS file: /home/mercury1/repository/mercury/analysis/analysis.file.m,v
retrieving revision 1.3
diff -u -r1.3 analysis.file.m
--- analysis/analysis.file.m	25 Jan 2006 03:21:03 -0000	1.3
+++ analysis/analysis.file.m	31 Jan 2006 05:50:53 -0000
@@ -13,6 +13,10 @@
 
 :- interface.
 
+:- pred read_module_overall_status(Compiler::in, module_id::in,
+	maybe(analysis_status)::out, io::di, io::uo) is det
+	<= compiler(Compiler).
+
 :- pred read_module_analysis_results(analysis_info::in, module_id::in,
 	analysis_status::out, module_analysis_map(analysis_result)::out,
 	io__state::di, io__state::uo) is det.
@@ -67,34 +71,60 @@
 :- func version_number = int.
 version_number = 2.
 
+:- func analysis_registry_suffix = string.
+analysis_registry_suffix = ".analysis".
+
+:- func imdg_suffix = string.
+imdg_suffix = ".imdg".
+
+:- func request_suffix = string.
+request_suffix = ".request".
+
 %-----------------------------------------------------------------------------%
 
-read_module_analysis_results(Info, ModuleId, ModuleStatus, ModuleResults,
-		!IO) :-
-	read_module_analysis_results_2(Info ^ compiler, ModuleId,
-		ModuleStatus, ModuleResults, !IO).
+read_module_overall_status(Compiler, ModuleId, MaybeModuleStatus, !IO) :-
+    module_id_to_file_name(Compiler, ModuleId, analysis_registry_suffix,
+	AnalysisFileName, !IO),
+    io__open_input(AnalysisFileName, OpenResult, !IO),
+    (
+	OpenResult = ok(Stream),
+	io__set_input_stream(Stream, OldStream, !IO),
 
-:- pred read_module_analysis_results_2(Compiler::in, module_id::in,
-	analysis_status::out, module_analysis_map(analysis_result)::out, 
-	io::di, io::uo) is det <= compiler(Compiler).
+	promise_only_solution_io(
+	    (pred(Status::out, !.IO::di, !:IO::uo) is cc_multi :-
+		try_io((pred(Status0::out, !.IO::di, !:IO::uo) is det :-
+		    check_analysis_file_version_number(!IO),
+		    read_module_status(Status0, !IO)
+		), Status, !IO)
+	    ), Result, !IO),
+	(
+	    Result = succeeded(ModuleStatus),
+	    MaybeModuleStatus = yes(ModuleStatus)
+	;
+	    Result = failed,
+	    MaybeModuleStatus = no
+	;
+	    Result = exception(_),
+	    % XXX Report error.
+	    MaybeModuleStatus = no
+	),
+	io__set_input_stream(OldStream, _, !IO),
+	io__close_input(Stream, !IO)
+    ;
+	OpenResult = error(_),
+	MaybeModuleStatus = no
+    ).
 
-read_module_analysis_results_2(Compiler, ModuleId, ModuleStatus, ModuleResults,
+read_module_analysis_results(Info, ModuleId, ModuleStatus, ModuleResults,
 		!IO) :-
-	read_analysis_file(Compiler, ModuleId, ".analysis",
+	% If the module's overall status is `invalid' then at least one of its
+	% results is invalid.  However, we can't just discard the results as we
+	% want to know which results change after we reanalyse the module.
+	Compiler = Info ^ compiler,
+	read_analysis_file(Compiler, ModuleId, analysis_registry_suffix,
 		read_module_status, optimal, ModuleStatus,
 		parse_result_entry(Compiler),
-		map__init, ModuleResults0, !IO),
-	% If the module's overall status is `invalid' then at least one 
-	% of its results is invalid so ignore them all.
-	(
-		( ModuleStatus = optimal
-		; ModuleStatus = suboptimal
-		),
-		ModuleResults = ModuleResults0
-	;
-		ModuleStatus = invalid,
-		ModuleResults = map.init
-	).
+		map__init, ModuleResults, !IO).
 
 :- pred read_module_status(analysis_status::out, io::di, io::uo) is det.
 
@@ -175,7 +205,7 @@
     ).
 
 read_module_analysis_requests(Info, ModuleId, ModuleRequests, !IO) :-
-	read_analysis_file(Info ^ compiler, ModuleId, ".request",
+	read_analysis_file(Info ^ compiler, ModuleId, request_suffix,
 		nop, unit, _NoHeader,
 		parse_request_entry(Info ^ compiler),
 		map__init, ModuleRequests, !IO).
@@ -231,7 +261,7 @@
     ).
 
 read_module_imdg(Info, ModuleId, ModuleEntries, !IO) :-
-    read_analysis_file(Info ^ compiler, ModuleId, ".imdg",
+    read_analysis_file(Info ^ compiler, ModuleId, imdg_suffix,
 	nop, unit, _NoHeader,
 	parse_imdg_arc(Info ^ compiler),
 	map.init, ModuleEntries, !IO).
@@ -299,6 +329,19 @@
 		ParseEntry, ModuleResults0, ModuleResults, !IO) :-
 	module_id_to_file_name(Compiler, ModuleId,
 		Suffix, AnalysisFileName, !IO),
+	read_analysis_file(AnalysisFileName,
+		ReadHeader, DefaultHeader, Header,
+		ParseEntry, ModuleResults0, ModuleResults, !IO).
+
+:- pred read_analysis_file(string::in,
+		read_analysis_header(Header)::in(read_analysis_header),
+		Header::in, Header::out,
+		parse_entry(T)::in(parse_entry), T::in, T::out,
+		io__state::di, io__state::uo) is det.
+
+read_analysis_file(AnalysisFileName,
+		ReadHeader, DefaultHeader, Header,
+		ParseEntry, ModuleResults0, ModuleResults, !IO) :-
 	io__open_input(AnalysisFileName, OpenResult, !IO),
 	(
 		OpenResult = ok(Stream),
@@ -383,9 +426,22 @@
 		io.print(ModuleId, !IO),
 		io.nl(!IO)
 	), !IO),
-	WriteHeader = write_module_status(ModuleStatus),
-	write_analysis_file(Info ^ compiler, ModuleId, ".analysis",
-		WriteHeader, write_result_entry, ModuleResults, !IO).
+	module_id_to_file_name(Info ^ compiler, ModuleId,
+		analysis_registry_suffix, AnalysisFileName, !IO),
+	file_exists(AnalysisFileName, FileExists, !IO),
+	(
+		FileExists = no,
+		ModuleStatus = optimal,
+		map__is_empty(ModuleResults)
+	->
+		% If the analysis file doesn't exist and there is no useful
+		% information to be written, leave the file as non-existant.
+		true
+	;
+		WriteHeader = write_module_status(ModuleStatus),
+		write_analysis_file(AnalysisFileName,
+			WriteHeader, write_result_entry, ModuleResults, !IO)
+	).
 
 :- pred write_module_status(analysis_status::in, io::di, io::uo) is det.
 
@@ -395,7 +451,7 @@
     analysis_status_to_string(Status, String).
 
 write_module_analysis_requests(Info, ModuleId, ModuleRequests, !IO) :-
-	module_id_to_file_name(Info ^ compiler, ModuleId, ".request",
+	module_id_to_file_name(Info ^ compiler, ModuleId, request_suffix,
 		AnalysisFileName, !IO),
 	debug_msg((pred(!.IO::di, !:IO::uo) is det :-
 		io.print("Writing module analysis requests to ", !IO),
@@ -436,7 +492,7 @@
 		Appended = no
 	),
 	( Appended = no ->
-		write_analysis_file(Info ^ compiler, ModuleId, ".request",
+		write_analysis_file(Info ^ compiler, ModuleId, request_suffix,
 			nop,
 			write_request_entry(Info ^ compiler),
 			ModuleRequests, !IO)
@@ -487,8 +543,18 @@
 		], context_init), !IO).
 
 write_module_imdg(Info, ModuleId, ModuleEntries, !IO) :-
-    write_analysis_file(Info ^ compiler, ModuleId, ".imdg",
-	nop, write_imdg_arc(Info ^ compiler), ModuleEntries, !IO).
+    module_id_to_file_name(Info ^ compiler, ModuleId, imdg_suffix, FileName,
+	!IO),
+    file_exists(FileName, FileExists, !IO),
+    (
+	FileExists = no,
+	map__is_empty(ModuleEntries)
+    ->
+	true
+    ;
+	write_analysis_file(Info ^ compiler, ModuleId, imdg_suffix,
+	    nop, write_imdg_arc(Info ^ compiler), ModuleEntries, !IO)
+    ).
 
 :- pred write_imdg_arc(Compiler::in)
 	    `with_type` write_entry(imdg_arc)
@@ -532,6 +598,15 @@
 		WriteEntry, ModuleResults, !IO) :-
 	module_id_to_file_name(Compiler, ModuleId,
 		Suffix, AnalysisFileName, !IO),
+	write_analysis_file(AnalysisFileName, WriteHeader,
+		WriteEntry, ModuleResults, !IO).
+
+:- pred write_analysis_file(string::in, write_header::in(write_header),
+	write_entry(T)::in(write_entry), module_analysis_map(T)::in,
+	io__state::di, io__state::uo) is det.
+
+write_analysis_file(AnalysisFileName, WriteHeader,
+		WriteEntry, ModuleResults, !IO) :-
 	io__open_output(AnalysisFileName, OpenResult, !IO),
 	(
 		OpenResult = ok(Stream),
@@ -567,7 +642,7 @@
 	    ), ModuleResults, !IO).
 
 empty_request_file(Info, ModuleId, !IO) :-
-	module_id_to_file_name(Info ^ compiler, ModuleId, ".request", 
+	module_id_to_file_name(Info ^ compiler, ModuleId, request_suffix,
 		RequestFileName, !IO),
 	debug_msg((pred(!.IO::di, !:IO::uo) is det :-
 		io.print("Removing request file ", !IO),
@@ -576,6 +651,19 @@
 	), !IO),
 	io__remove_file(RequestFileName, _, !IO).
 
+:- pred file_exists(string::in, bool::out, io::di, io::uo) is det.
+
+file_exists(FileName, Exists, !IO) :-
+    io.open_input(FileName, Result, !IO),
+    (
+	Result = ok(Stream),
+	io.close_input(Stream, !IO),
+	Exists = yes
+    ;
+	Result = error(_),
+	Exists = no
+    ).
+
 :- pred nop(io::di, io::uo) is det.
 
 nop(!IO).
Index: analysis/analysis.m
===================================================================
RCS file: /home/mercury1/repository/mercury/analysis/analysis.m,v
retrieving revision 1.3
diff -u -r1.3 analysis.m
--- analysis/analysis.m	25 Jan 2006 03:21:03 -0000	1.3
+++ analysis/analysis.m	31 Jan 2006 05:52:08 -0000
@@ -199,8 +199,15 @@
 	% requests and results for the current compilation to the
 	% analysis files.
 	%
-:- pred write_analysis_files(module_id::in, set(module_id)::in, 
-	analysis_info::in, analysis_info::out, io::di, io::uo) is det.
+:- pred write_analysis_files(Compiler::in, module_id::in, set(module_id)::in, 
+	analysis_info::in, analysis_info::out, io::di, io::uo) is det
+	<= compiler(Compiler).
+
+:- pred read_module_overall_status(Compiler::in, module_id::in,
+	maybe(analysis_status)::out, io::di, io::uo) is det
+	<= compiler(Compiler).
+
+:- pred enable_debug_messages(bool::in, io::di, io::uo) is det.
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
@@ -317,6 +324,15 @@
 %-----------------------------------------------------------------------------%
 
 lookup_results(ModuleId, FuncId, ResultList, !Info, !IO) :-
+    lookup_results(no, ModuleId, FuncId, ResultList, !Info, !IO).
+
+:- pred lookup_results(bool::in, module_id::in, func_id::in,
+	list({Call, Answer, analysis_status})::out, 
+	analysis_info::in, analysis_info::out, io::di, io::uo) is det
+	<= analysis(Call, Answer).
+
+lookup_results(AllowInvalidModules, ModuleId, FuncId, ResultList,
+	!Info, !IO) :-
     debug_msg((pred(!.IO::di, !:IO::uo) is det :-
 	io.write_string("Looking up analysis results for ", !IO),
 	io.write_string(ModuleId, !IO),
@@ -325,13 +341,20 @@
 	io.nl(!IO)
     ), !IO),
     ensure_old_module_analysis_results_loaded(ModuleId, !Info, !IO),
-    lookup_results_2(!.Info ^ old_analysis_results,
-	ModuleId, FuncId, ResultList),
-    debug_msg((pred(!.IO::di, !:IO::uo) is det :-
-	io.write_string("Found these results: ", !IO),
-	io.print(ResultList, !IO),
-	io.nl(!IO)
-    ), !IO).
+    (if
+	AllowInvalidModules = no,
+	!.Info ^ module_statuses ^ det_elem(ModuleId) = invalid
+    then
+	ResultList = []
+    else
+	lookup_results_2(!.Info ^ old_analysis_results,
+	    ModuleId, FuncId, ResultList),
+	debug_msg((pred(!.IO::di, !:IO::uo) is det :-
+	    io.write_string("Found these results: ", !IO),
+	    io.print(ResultList, !IO),
+	    io.nl(!IO)
+	), !IO)
+    ).
 
 :- pred lookup_results_2(analysis_map(analysis_result)::in, module_id::in,
 	func_id::in, list({Call, Answer, analysis_status})::out) is det
@@ -405,14 +428,14 @@
 	Best = Best0
     ).
 
-:- pred lookup_exactly_matching_result(module_id::in, func_id::in, Call::in,
-	maybe({Call, Answer, analysis_status})::out, 
+:- pred lookup_exactly_matching_result_even_from_invalid_modules(module_id::in,
+	func_id::in, Call::in, maybe({Call, Answer, analysis_status})::out,
 	analysis_info::in, analysis_info::out, io::di, io::uo) is det
 	<= analysis(Call, Answer).
 
-lookup_exactly_matching_result(ModuleId, FuncId, Call, MaybeResult,
-        !Info, !IO) :-
-    lookup_results(ModuleId, FuncId, AllResultsList, !Info, !IO),
+lookup_exactly_matching_result_even_from_invalid_modules(ModuleId,
+	FuncId, Call, MaybeResult, !Info, !IO) :-
+    lookup_results(yes, ModuleId, FuncId, AllResultsList, !Info, !IO),
     ResultList = list.filter(
         (pred(({ResultCall, _, _})::in) is semidet :-
                 equivalent(Call, ResultCall)
@@ -614,8 +637,8 @@
 update_analysis_registry_5(ModuleId, AnalysisName, FuncId, NewResult,
 	!Info, !IO) :-
     NewResult = analysis_result(Call, NewAnswer, NewStatus),
-    lookup_exactly_matching_result(ModuleId, FuncId, Call, MaybeResult,
-	!Info, !IO),
+    lookup_exactly_matching_result_even_from_invalid_modules(ModuleId, FuncId,
+	Call, MaybeResult, !Info, !IO),
     (
 	% There was a previous answer for this call pattern.
 	%
@@ -878,7 +901,7 @@
     % and will write out data currently cached in the analysis_info
     % structure out to disk.
     % 
-write_analysis_files(ModuleId, ImportedModuleIds, !Info, !IO) :-
+write_analysis_files(Compiler, ModuleId, ImportedModuleIds, !Info, !IO) :-
     % The current module was just compiled so we set its status to the
     % lub of all the new analysis results generated.
     (if NewResults = !.Info ^ new_analysis_results ^ elem(ModuleId) then
@@ -916,7 +939,21 @@
     empty_request_file(!.Info, ModuleId, !IO),
 
     % Write the intermodule dependency graphs.
-    map.foldl(write_module_imdg(!.Info), !.Info ^ old_imdg, !IO).
+    map.foldl(write_module_imdg(!.Info), !.Info ^ old_imdg, !IO),
+    
+    % Touch a timestamp file to indicate the last time that this module was
+    % analysed.
+    module_id_to_file_name(Compiler, ModuleId, ".analysis_date",
+	TimestampFileName, !IO),
+    io.open_output(TimestampFileName, Result, !IO),
+    (
+        Result = ok(OutputStream),
+        io.write_string(OutputStream, "\n", !IO),
+        io.close_output(OutputStream, !IO)
+    ;
+        Result = error(IOError),
+	error(io.error_message(IOError))
+    ).
 
 :- pred write_analysis_files_2(analysis_info::in, module_id::in,
 	module_analysis_map(analysis_result)::in, io::di, io::uo) is det.
@@ -928,6 +965,12 @@
 
 %-----------------------------------------------------------------------------%
 
+read_module_overall_status(Compiler, ModuleId, MaybeModuleStatus, !IO) :-
+    analysis.file.read_module_overall_status(Compiler, ModuleId,
+	MaybeModuleStatus, !IO).
+
+%-----------------------------------------------------------------------------%
+
 lub(StatusA, StatusB) = Status :-
     compare(Cmp, StatusA, StatusB),
     (
@@ -961,13 +1004,19 @@
 
 %-----------------------------------------------------------------------------%
 
-% XXX make this enableable with a command-line option.  A problem is that we
-% don't want to make the analysis directory dependent on anything in the
-% compiler directory.
+:- mutable(debug_analysis, bool, no, ground, [untrailed, attach_to_io_state]).
+
+enable_debug_messages(Debug, !IO) :-
+    set_debug_analysis(Debug, !IO).
 
 :- pred debug_msg(pred(io, io)::in(pred(di, uo) is det), io::di, io::uo)
     is det.
 
-debug_msg(_P, !IO) :-
-    % P(!IO),
-    true.
+debug_msg(P, !IO) :-
+    get_debug_analysis(Debug, !IO),
+    (
+	Debug = yes,
+	P(!IO)
+    ;
+	Debug = no
+    ).
Index: compiler/exception_analysis.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/exception_analysis.m,v
retrieving revision 1.18
diff -u -r1.18 exception_analysis.m
--- compiler/exception_analysis.m	1 Feb 2006 04:02:45 -0000	1.18
+++ compiler/exception_analysis.m	1 Feb 2006 05:15:58 -0000
@@ -211,9 +211,10 @@
     %
     % Record the analysis results for intermodule analysis.
     %
-    globals.io_lookup_bool_option(intermodule_analysis, IntermodAnalysis, !IO),
+    globals.io_lookup_bool_option(make_analysis_registry,
+        MakeAnalysisRegistry, !IO),
     (
-        IntermodAnalysis = yes,
+        MakeAnalysisRegistry = yes,
         (
             MaybeAnalysisStatus = yes(AnalysisStatus),
             record_exception_analysis_results(Status, AnalysisStatus, SCC,
@@ -224,7 +225,7 @@
                 "check_scc_for_exceptions: no analysis status.")
         )
     ;
-        IntermodAnalysis = no
+        MakeAnalysisRegistry = no
     ).
 
     % Check each procedure in the SCC individually.
@@ -985,20 +986,33 @@
     Call = any_call,
     lookup_best_result(ModuleId, FuncId, Call, MaybeBestStatus, !AnalysisInfo,
         !IO),
+    globals__io_lookup_bool_option(make_analysis_registry,
+        MakeAnalysisRegistry, !IO),
     (
         MaybeBestStatus = yes({BestCall, exception_analysis_answer(Result),
             AnalysisStatus}),
-        record_dependencies(ModuleId, FuncId, BestCall, ModuleInfo, CallerSCC,
-            !AnalysisInfo)
+        (
+            MakeAnalysisRegistry = yes,
+            record_dependencies(ModuleId, FuncId, BestCall, ModuleInfo,
+                CallerSCC, !AnalysisInfo)
+        ;
+            MakeAnalysisRegistry = no
+        )
     ;
         MaybeBestStatus = no,
         % If we do not have any information about the callee procedure then
         % assume that it throws an exception.
         top(Call) = exception_analysis_answer(Result),
         AnalysisStatus = suboptimal,
-        record_request(analysis_name, ModuleId, FuncId, Call, !AnalysisInfo),
-        record_dependencies(ModuleId, FuncId, Call, ModuleInfo, CallerSCC,
-            !AnalysisInfo)
+        (
+            MakeAnalysisRegistry = yes,
+            record_request(analysis_name, ModuleId, FuncId, Call,
+                !AnalysisInfo),
+            record_dependencies(ModuleId, FuncId, Call, ModuleInfo, CallerSCC,
+                !AnalysisInfo)
+        ;
+            MakeAnalysisRegistry = no
+        )
     ).
 
     % XXX If the procedures in CallerSCC definitely come from the
Index: compiler/handle_options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/handle_options.m,v
retrieving revision 1.251
diff -u -r1.251 handle_options.m
--- compiler/handle_options.m	31 Jan 2006 05:20:40 -0000	1.251
+++ compiler/handle_options.m	1 Feb 2006 03:42:31 -0000
@@ -78,6 +78,7 @@
 
 :- implementation.
 
+:- import_module analysis.
 :- import_module libs.compiler_util.
 :- import_module libs.trace_params.
 :- import_module parse_tree.
@@ -120,6 +121,8 @@
             MakeOptimizationInt, !IO),
         globals__io_lookup_bool_option(make_transitive_opt_interface,
             MakeTransOptInt, !IO),
+        globals__io_lookup_bool_option(make_analysis_registry,
+            MakeAnalysisRegistry, !IO),
         globals__io_lookup_bool_option(convert_to_mercury,
             ConvertToMercury, !IO),
         globals__io_lookup_bool_option(typecheck_only, TypecheckOnly, !IO),
@@ -132,7 +135,7 @@
         globals__io_lookup_bool_option(aditi_only, AditiOnly, !IO),
         bool__or_list([GenerateDependencies, GenerateDependencyFile,
             MakeInterface, MakePrivateInterface, MakeShortInterface,
-            MakeOptimizationInt, MakeTransOptInt,
+            MakeOptimizationInt, MakeTransOptInt, MakeAnalysisRegistry,
             ConvertToMercury, TypecheckOnly,
             ErrorcheckOnly, TargetCodeOnly,
             GenerateIL, CompileOnly, AditiOnly],
@@ -747,6 +750,8 @@
             smart_recompilation, bool(no), !Globals),
         option_implies(make_transitive_opt_interface,
             smart_recompilation, bool(no), !Globals),
+        option_implies(make_analysis_registry,
+            smart_recompilation, bool(no), !Globals),
         option_implies(errorcheck_only, smart_recompilation, bool(no),
             !Globals),
         option_implies(typecheck_only, smart_recompilation, bool(no),
@@ -853,6 +858,10 @@
             true
         ),
 
+        globals__lookup_bool_option(!.Globals, debug_intermodule_analysis,
+            DebugIntermoduleAnalysis),
+        analysis__enable_debug_messages(DebugIntermoduleAnalysis, !IO),
+
         globals__lookup_int_option(!.Globals, dump_hlds_pred_id,
             DumpHLDSPredId),
         ( DumpHLDSPredId >= 0 ->
Index: compiler/make.dependencies.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/make.dependencies.m,v
retrieving revision 1.23
diff -u -r1.23 make.dependencies.m
--- compiler/make.dependencies.m	25 Jan 2006 03:27:35 -0000	1.23
+++ compiler/make.dependencies.m	31 Jan 2006 04:27:04 -0000
@@ -213,7 +213,6 @@
             short_interface `of` non_intermod_indirect_imports
         ]).
 target_dependencies(_, analysis_registry) = 
-    % XXX not sure about this.
     combine_deps_list([
         source `of` self,
         private_interface `of` parents,
@@ -263,9 +262,11 @@
 
 compiled_code_dependencies(Globals) = Deps :-
     globals__lookup_bool_option(Globals, intermodule_optimization, Intermod),
+    globals__lookup_bool_option(Globals, intermodule_analysis,
+        IntermodAnalysis),
     (
         Intermod = yes,
-        Deps = combine_deps_list([
+        Deps0 = combine_deps_list([
             intermodule_interface `of` self,
             intermodule_interface `of` intermod_imports,
             map_find_module_deps(imports,
@@ -274,7 +275,18 @@
         ])
     ;
         Intermod = no,
-        Deps = compiled_code_dependencies
+        Deps0 = compiled_code_dependencies
+    ),
+    (
+        IntermodAnalysis = yes,
+        Deps = combine_deps_list([
+            analysis_registry `of` self,
+            analysis_registry `of` direct_imports,
+            Deps0
+        ])
+    ;
+        IntermodAnalysis = no,
+        Deps = Deps0
     ).
 
 :- func compiled_code_dependencies =
Index: compiler/make.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/make.m,v
retrieving revision 1.32
diff -u -r1.32 make.m
--- compiler/make.m	25 Jan 2006 03:27:35 -0000	1.32
+++ compiler/make.m	31 Jan 2006 00:19:05 -0000
@@ -144,8 +144,10 @@
         importing_module        :: maybe(module_name),
 
         % Targets specified on the command line.
-        command_line_targets    :: set(pair(module_name, target_type))
+        command_line_targets    :: set(pair(module_name, target_type)),
 
+        % Number of repeated passes of analysis allowed.
+        reanalysis_passes       :: int
     ).
 
 :- type make_error
@@ -205,6 +207,7 @@
     --->    clean
     ;       realclean
     ;       build_all(module_target_type)
+    ;       build_analyses
     ;       build_library
     ;       install_library.
 
@@ -277,12 +280,15 @@
             ClassifiedTargets),
 
         ShouldRebuildDeps = yes,
+        globals__io_lookup_int_option(max_reanalysis_passes,
+            MaxReanalysisPasses, !IO),
         MakeInfo0 = make_info(map__init, map__init, OptionArgs, Variables,
             map__init,
             init_cached_direct_imports,
             init_cached_transitive_dependencies,
             ShouldRebuildDeps, KeepGoing,
-            set__init, no, set__list_to_set(ClassifiedTargets)),
+            set__init, no, set__list_to_set(ClassifiedTargets),
+            MaxReanalysisPasses),
 
         %
         % Build the targets, stopping on any errors if
@@ -390,6 +396,11 @@
         ModuleNameStr = ModuleNameStr0,
         TargetType = misc_target(build_all(errors))
     ;
+        Suffix = ".analyse"
+    ->
+        ModuleNameStr = ModuleNameStr0,
+        TargetType = misc_target(build_analyses)
+    ;
         Suffix = ".clean"
     ->
         ModuleNameStr = ModuleNameStr0,
Index: compiler/make.module_target.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/make.module_target.m,v
retrieving revision 1.35
diff -u -r1.35 make.module_target.m
--- compiler/make.module_target.m	25 Jan 2006 03:27:35 -0000	1.35
+++ compiler/make.module_target.m	31 Jan 2006 05:57:37 -0000
@@ -60,8 +60,11 @@
 
 :- implementation.
 
+:- import_module analysis.
 :- import_module hlds.passes_aux.
 :- import_module libs.compiler_util.
+:- import_module transform_hlds.
+:- import_module transform_hlds.mmc_analysis.
 
 %-----------------------------------------------------------------------------%
 
@@ -231,22 +234,52 @@
         debug_file_msg(TargetFile, "target file does not exist", !IO),
         DepsResult = out_of_date
     ;
-        %
-        % Compare the oldest of the timestamps of the touched
-        % files with the timestamps of the dependencies.
-        %
-        list__map_foldl2(get_timestamp_file_timestamp,
-            TouchedTargetFiles, TouchedTargetFileTimestamps, !Info, !IO),
-        list__map_foldl2(get_file_timestamp([dir__this_directory]),
-            TouchedFiles, TouchedFileTimestamps, !Info, !IO),
-        MaybeOldestTimestamp0 = list__foldl(find_oldest_timestamp,
-            TouchedTargetFileTimestamps, ok(newest_timestamp)),
-        MaybeOldestTimestamp = list__foldl(find_oldest_timestamp,
-            TouchedFileTimestamps, MaybeOldestTimestamp0),
-
-        get_file_name(no, TargetFile, TargetFileName, !Info, !IO),
-        check_dependencies(TargetFileName, MaybeOldestTimestamp,
-            MakeDepsSuccess, DepFilesToMake, DepsResult, !Info, !IO)
+        ( TargetFile = ModuleName - analysis_registry ->
+            force_reanalysis_of_suboptimal_module(ModuleName, ForceReanalysis,
+                !.Info, !IO)
+        ;
+            ForceReanalysis = no
+        ),
+        (
+            ForceReanalysis = yes,
+            DepsResult = out_of_date
+        ;
+            ForceReanalysis = no,
+            %
+            % Compare the oldest of the timestamps of the touched
+            % files with the timestamps of the dependencies.
+            %
+            list__map_foldl2(get_timestamp_file_timestamp,
+                TouchedTargetFiles, TouchedTargetFileTimestamps, !Info, !IO),
+            list__map_foldl2(get_file_timestamp([dir__this_directory]),
+                TouchedFiles, TouchedFileTimestamps, !Info, !IO),
+            MaybeOldestTimestamp0 = list__foldl(find_oldest_timestamp,
+                TouchedTargetFileTimestamps, ok(newest_timestamp)),
+            MaybeOldestTimestamp = list__foldl(find_oldest_timestamp,
+                TouchedFileTimestamps, MaybeOldestTimestamp0),
+    
+            get_file_name(no, TargetFile, TargetFileName, !Info, !IO),
+            check_dependencies(TargetFileName, MaybeOldestTimestamp,
+                MakeDepsSuccess, DepFilesToMake, DepsResult, !Info, !IO)
+        )
+    ).
+
+:- pred force_reanalysis_of_suboptimal_module(module_name::in, bool::out,
+    make_info::in, io::di, io::uo) is det.
+                
+force_reanalysis_of_suboptimal_module(ModuleName, ForceReanalysis, Info,
+        !IO) :-
+    (if Info ^ reanalysis_passes > 0 then
+        ModuleId = module_name_to_module_id(ModuleName),
+        analysis__read_module_overall_status(mmc, ModuleId,
+            MaybeAnalysisStatus, !IO),
+        ( MaybeAnalysisStatus = yes(suboptimal) ->
+            ForceReanalysis = yes
+        ;
+            ForceReanalysis = no
+        )
+    else
+        ForceReanalysis = no
     ).
 
 %-----------------------------------------------------------------------------%
@@ -332,7 +365,8 @@
     io__set_output_stream(ErrorStream, OldOutputStream, !IO),
     ( 
         (ModuleTask = compile_to_target_code
-        ; ModuleTask = make_optimization_interface)
+        ; ModuleTask = make_optimization_interface
+        ; ModuleTask = make_analysis_registry)
      ->
         call_in_forked_process(call_mercury_compile_main([ModuleArg]),
             invoke_mmc(ErrorStream, ArgFileName, AllOptionArgs ++ [ModuleArg]),
@@ -623,7 +657,7 @@
     process_module(make_optimization_interface) -
         ["--make-optimization-interface"].
 compilation_task(_, analysis_registry) =
-    sorry(this_file, ".analysis targets").
+    process_module(make_analysis_registry) - ["--make-analysis-registry"].
 compilation_task(_, aditi_code) =
     process_module(compile_to_target_code) - ["--aditi-only"].
 compilation_task(Globals, c_header(_)) = compilation_task(Globals, c_code).
Index: compiler/make.program_target.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/make.program_target.m,v
retrieving revision 1.37
diff -u -r1.37 make.program_target.m
--- compiler/make.program_target.m	25 Jan 2006 03:27:35 -0000	1.37
+++ compiler/make.program_target.m	31 Jan 2006 05:57:42 -0000
@@ -40,8 +40,11 @@
 
 :- implementation.
 
+:- import_module analysis.
 :- import_module hlds.passes_aux.
 :- import_module libs.compiler_util.
+:- import_module transform_hlds.
+:- import_module transform_hlds.mmc_analysis.
 
 %-----------------------------------------------------------------------------%
 
@@ -63,9 +66,29 @@
     ->
         Succeeded = yes
     ;
-        build_with_module_options(MainModuleName, ExtraOptions,
-            make_linked_target_2(MainModuleName - FileType),
-            Succeeded, !Info, !IO)
+        % When using `--intermodule-analysis', perform an analysis pass first.
+        % The analysis of one module may invalidate the results of a module we
+        % analysed earlier, so this step must be carried out until all the
+        % `.analysis' are in a valid state before we can continue.
+        globals__io_lookup_bool_option(intermodule_analysis,
+            IntermoduleAnalysis, !IO),
+        (
+            IntermoduleAnalysis = yes,
+            make_misc_target(MainModuleName - build_analyses,
+                ExtraOptions, Succeeded0, !Info, !IO)
+        ;
+            IntermoduleAnalysis = no,
+            Succeeded0 = yes
+        ),
+        (
+            Succeeded0 = yes,
+            build_with_module_options(MainModuleName, ExtraOptions,
+                make_linked_target_2(MainModuleName - FileType),
+                Succeeded, !Info, !IO)
+        ;
+            Succeeded0 = no,
+            Succeeded = no
+        )
     ).
 
 :- pred make_linked_target_2(linked_target_file::in, list(string)::in,
@@ -501,6 +524,10 @@
             Succeeded = Succeeded0 `and` Succeeded1
         )
     ;
+        TargetType = build_analyses,
+        build_analyses(MainModuleName, AllModules, Succeeded0, Succeeded,
+            !Info, !IO)
+    ;
         TargetType = build_library,
         ShortInts = make_dependency_list(AllModules,
             unqualified_short_interface),
@@ -565,6 +592,99 @@
         )
     ).
 
+:- pred build_analyses(module_name::in, list(module_name)::in,
+    bool::in, bool::out, make_info::in, make_info::out, io::di, io::uo)
+    is det.
+
+build_analyses(MainModuleName, AllModules, Succeeded0, Succeeded,
+        !Info, !IO) :-
+    get_target_modules(analysis_registry, AllModules, TargetModules,
+        !Info, !IO),
+    globals__io_lookup_bool_option(keep_going, KeepGoing, !IO),
+    ( Succeeded0 = no, KeepGoing = no ->
+        Succeeded = no
+    ;
+        foldl2_maybe_stop_at_error(KeepGoing,
+            make_module_target,
+            make_dependency_list(TargetModules, analysis_registry),
+            Succeeded1, !Info, !IO),
+        
+        % Find which module analysis files are suboptimal or invalid.
+        % If there are any invalid files then we repeat the analysis pass.
+        % If there are only suboptimal files then we repeat the analysis up
+        % to the number of times given by the user.
+        ReanalysisPasses = !.Info ^ reanalysis_passes,
+        ReanalyseSuboptimal = (if ReanalysisPasses > 1 then yes else no),
+        modules_needing_reanalysis(ReanalyseSuboptimal, TargetModules,
+            InvalidModules, SuboptimalModules, !IO),
+        ( list__is_not_empty(InvalidModules) ->
+            maybe_reanalyse_modules_message(!IO),
+            list__foldl(reset_analysis_registry_dependency_status,
+                InvalidModules, !Info),
+            build_analyses(MainModuleName, AllModules, Succeeded0, Succeeded,
+                !Info, !IO)
+        ; list__is_not_empty(SuboptimalModules) ->
+            list__foldl(reset_analysis_registry_dependency_status,
+                SuboptimalModules, !Info),
+            !:Info = !.Info ^ reanalysis_passes := ReanalysisPasses - 1,
+            maybe_reanalyse_modules_message(!IO),
+            build_analyses(MainModuleName, AllModules, Succeeded0, Succeeded,
+                !Info, !IO)
+        ;
+            Succeeded = Succeeded0 `and` Succeeded1
+        )
+    ).
+
+:- pred modules_needing_reanalysis(bool::in, list(module_name)::in,
+    list(module_name)::out, list(module_name)::out, io::di, io::uo) is det.
+
+modules_needing_reanalysis(_, [], [], [], !IO).
+modules_needing_reanalysis(ReanalyseSuboptimal, [Module | Modules],
+        InvalidModules, SuboptimalModules, !IO) :-
+    analysis.read_module_overall_status(mmc, module_name_to_module_id(Module),
+        MaybeModuleStatus, !IO),
+    (
+        MaybeModuleStatus = yes(ModuleStatus),
+        (
+            ModuleStatus = optimal,
+            modules_needing_reanalysis(ReanalyseSuboptimal, Modules,
+                InvalidModules, SuboptimalModules, !IO)
+        ;
+            ModuleStatus = suboptimal,
+            modules_needing_reanalysis(ReanalyseSuboptimal, Modules,
+                InvalidModules, SuboptimalModules0, !IO),
+            (
+                ReanalyseSuboptimal = yes,
+                SuboptimalModules = [Module | SuboptimalModules0]
+            ;
+                ReanalyseSuboptimal = no,
+                SuboptimalModules = SuboptimalModules0
+            )
+        ;
+            ModuleStatus = invalid,
+            modules_needing_reanalysis(ReanalyseSuboptimal, Modules,
+                InvalidModules0, SuboptimalModules, !IO),
+            InvalidModules = [Module | InvalidModules0]
+        )
+    ;
+        MaybeModuleStatus = no,
+        % The analysis file does not exist.  The file might be optimal and
+        % without any analysis results, or for some reason it wasn't created
+        % in this or an earlier pass (and hence probably won't be created
+        % no matter how many times we repeat the analysis).
+        %
+        % XXX: MaybeModuleStatus could be `no' for some other reason
+        modules_needing_reanalysis(ReanalyseSuboptimal, Modules,
+            InvalidModules, SuboptimalModules, !IO)
+    ).
+
+:- pred reset_analysis_registry_dependency_status(module_name::in,
+    make_info::in, make_info::out) is det.
+
+reset_analysis_registry_dependency_status(ModuleName, Info,
+        Info ^ dependency_status ^ elem(Dep) := not_considered) :-
+    Dep = target(ModuleName - analysis_registry).
+
 :- pred shared_libraries_supported(bool::out, io::di, io::uo) is det.
 
 shared_libraries_supported(Supported, !IO) :-
Index: compiler/make.util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/make.util.m,v
retrieving revision 1.29
diff -u -r1.29 make.util.m
--- compiler/make.util.m	25 Jan 2006 03:27:35 -0000	1.29
+++ compiler/make.util.m	31 Jan 2006 05:57:29 -0000
@@ -240,6 +240,11 @@
 :- pred maybe_make_target_message(io__output_stream::in, target_file::in,
     io::di, io::uo) is det.
 
+    % Write a message "Reanalysing invalid/suboptimal modules" if
+    % `--verbose-make' is set.
+    %
+:- pred maybe_reanalyse_modules_message(io::di, io::uo) is det.
+
     % Write a message "** Error making <filename>".
     %
 :- pred target_file_error(target_file::in, io::di, io::uo) is det.
@@ -259,7 +264,10 @@
 
 :- implementation.
 
+:- import_module analysis.
 :- import_module libs.compiler_util.
+:- import_module transform_hlds.
+:- import_module transform_hlds.mmc_analysis.
 
 %-----------------------------------------------------------------------------%
 
@@ -559,7 +567,51 @@
         MaybeTimestamp = MaybeTimestamp0
     ).
 
-get_target_timestamp(Search, ModuleName - FileType, MaybeTimestamp,
+get_target_timestamp(Search, Target, MaybeTimestamp, !Info, !IO) :-
+    ( Target = ModuleName - analysis_registry ->
+        get_target_timestamp_analysis_registry(Search, ModuleName,
+            MaybeTimestamp, !Info, !IO)
+    ;
+        get_target_timestamp_2(Search, Target, MaybeTimestamp, !Info, !IO)
+    ).
+
+    % Special treatment for `.analysis' files.  If the `.analysis' file is
+    % valid then we look at the corresponding `.analysis_date' file to get the
+    % last time that the module was actually analysed (the file may have been
+    % rewritten or had it's status changed while analysing other modules).
+    % If the `.analysis' file is invalid then we treat it as out of date.
+    %
+:- pred get_target_timestamp_analysis_registry(bool::in, module_name::in,
+    maybe_error(timestamp)::out, make_info::in, make_info::out,
+    io::di, io::uo) is det.
+
+get_target_timestamp_analysis_registry(Search, ModuleName, MaybeTimestamp,
+        !Info, !IO) :-
+    ModuleId = module_name_to_module_id(ModuleName),
+    analysis.read_module_overall_status(mmc, ModuleId, MaybeStatus, !IO),
+    (
+        MaybeStatus = yes(Status),
+        (
+            ( Status = optimal
+            ; Status = suboptimal
+            ),
+            get_timestamp_file_timestamp(ModuleName - analysis_registry,
+                MaybeTimestamp, !Info, !IO)
+        ;
+            Status = invalid,
+            MaybeTimestamp = error("invalid module")
+        )
+    ;
+        MaybeStatus = no,
+        get_target_timestamp_2(Search, ModuleName - analysis_registry,  
+            MaybeTimestamp, !Info, !IO)
+    ).
+
+:- pred get_target_timestamp_2(bool::in, target_file::in,
+    maybe_error(timestamp)::out, make_info::in, make_info::out,
+    io::di, io::uo) is det.
+
+get_target_timestamp_2(Search, ModuleName - FileType, MaybeTimestamp,
         !Info, !IO) :-
     get_file_name(Search, ModuleName - FileType, FileName, !Info, !IO),
     (
@@ -572,11 +624,14 @@
     get_file_timestamp(SearchDirs, FileName, MaybeTimestamp0, !Info, !IO),
     (
         MaybeTimestamp0 = error(_),
-        FileType = intermodule_interface
+        ( FileType = intermodule_interface
+        ; FileType = analysis_registry
+        )
     ->
         % If a `.opt' file in another directory doesn't exist,
         % it just means that a library wasn't compiled with
         % `--intermodule-optimization'.
+        % Similarly for `.analysis' files.
 
         get_module_dependencies(ModuleName, MaybeImports, !Info, !IO),
         (
@@ -826,12 +881,18 @@
     % Note that we need a timestamp file for `.err' files because
     % errors are written to the `.err' file even when writing interfaces.
     % The timestamp is only updated when compiling to target code.
+    %
+    % We need a timestamp file for `.analysis' files because they
+    % can be modified in the process of analysing _another_ module.
+    % The timestamp is only updated after actually analysing the module that
+    % the `.analysis' file corresponds to.
 timestamp_extension(_, errors) = ".err_date".
 timestamp_extension(_, private_interface) = ".date0".
 timestamp_extension(_, long_interface) = ".date".
 timestamp_extension(_, short_interface) = ".date".
 timestamp_extension(_, unqualified_short_interface) = ".date3".
 timestamp_extension(_, intermodule_interface) = ".optdate".
+timestamp_extension(_, analysis_registry) = ".analysis_date".
 timestamp_extension(_, c_code) = ".c_date".
 timestamp_extension(Globals, c_header(_)) = Ext :-
     globals__get_target(Globals, Target),
@@ -954,6 +1015,15 @@
             io__set_output_stream(OldOutputStream, _)
         ), !IO).
 
+maybe_reanalyse_modules_message(!IO) :-
+    io__output_stream(OutputStream, !IO),
+    verbose_msg(
+        (pred(!.IO::di, !:IO::uo) is det :-
+            io__set_output_stream(OutputStream, OldOutputStream, !IO),
+            io__write_string("Reanalysing invalid/suboptimal modules\n", !IO),
+            io__set_output_stream(OldOutputStream, _, !IO)
+        ), !IO).
+
 target_file_error(TargetFile, !IO) :-
     io__write_string("** Error making `", !IO),
     write_target_file(TargetFile, !IO),
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.374
diff -u -r1.374 mercury_compile.m
--- compiler/mercury_compile.m	1 Feb 2006 04:02:46 -0000	1.374
+++ compiler/mercury_compile.m	1 Feb 2006 05:10:26 -0000
@@ -543,6 +543,7 @@
         generate_dependency_file, make_interface,
         make_short_interface, make_private_interface,
         make_optimization_interface, make_transitive_opt_interface,
+        make_analysis_registry,
         typecheck_only, errorcheck_only],
     BoolList = list__map((func(Opt) = Bool :-
         globals__lookup_bool_option(Globals, Opt, Bool)),
@@ -1438,6 +1439,8 @@
             MakeOptInt, !IO),
         globals__io_lookup_bool_option(make_transitive_opt_interface,
             MakeTransOptInt, !IO),
+        globals__io_lookup_bool_option(make_analysis_registry,
+            MakeAnalysisRegistry, !IO),
         ( TypeCheckOnly = yes ->
             FactTableObjFiles = []
         ; ErrorCheckOnly = yes ->
@@ -1460,6 +1463,9 @@
         ; MakeTransOptInt = yes ->
             output_trans_opt_file(HLDS21, !DumpInfo, !IO),
             FactTableObjFiles = []
+        ; MakeAnalysisRegistry = yes ->
+            output_analysis_file(ModuleName, HLDS21, _HLDS, !DumpInfo, !IO),
+            FactTableObjFiles = []
         ;
             mercury_compile_after_front_end(NestedSubModules,
                 FindTimestampFiles, MaybeTimestamps, ModuleName, HLDS21,
@@ -1507,21 +1513,6 @@
     % magic sets can report errors.
     module_info_get_num_errors(!.HLDS, NumErrors),
     ( NumErrors = 0 ->
-        globals__io_lookup_bool_option(intermodule_analysis, IntermodAnalysis,
-            !IO),
-        (
-            IntermodAnalysis = yes,
-            module_info_get_analysis_info(!.HLDS, AnalysisInfo0),
-            module_info_get_all_deps(!.HLDS, ImportedModules),
-            ModuleId = module_name_to_module_id(ModuleName),
-            ImportedModuleIds = set.map(module_name_to_module_id,
-                ImportedModules),
-            analysis__write_analysis_files(ModuleId, ImportedModuleIds,
-                AnalysisInfo0, AnalysisInfo, !IO),
-            module_info_set_analysis_info(AnalysisInfo, !HLDS)
-        ;
-            IntermodAnalysis = no
-        ),
         maybe_generate_rl_bytecode(Verbose, MaybeRLFile, !HLDS, !IO),
         (
             ( Target = c
@@ -2197,6 +2188,49 @@
     maybe_dump_hlds(!.HLDS, 167, "trail_usage", !DumpInfo, !IO),
     trans_opt__write_optfile(!.HLDS, !IO).
 
+    % XXX: this is largely a duplicate of output_trans_opt_file
+    %
+:- pred output_analysis_file(module_name::in,
+    module_info::in, module_info::out, dump_info::in, dump_info::out,
+    io::di, io::uo) is det.
+
+output_analysis_file(ModuleName, !HLDS, !DumpInfo, !IO) :-
+    globals__io_lookup_bool_option(verbose, Verbose, !IO),
+    globals__io_lookup_bool_option(statistics, Stats, !IO),
+    globals__io_lookup_bool_option(analyse_closures, ClosureAnalysis, !IO),
+    %
+    % Closure analysis assumes that lambda expressions have
+    % been converted into separate predicates.
+    %
+    (
+        ClosureAnalysis = yes,
+        process_lambdas(Verbose, Stats, !HLDS, !IO)
+    ;
+        ClosureAnalysis = no
+    ),
+    maybe_dump_hlds(!.HLDS, 110, "lambda", !DumpInfo, !IO),
+    maybe_closure_analysis(Verbose, Stats, !HLDS, !IO),
+    maybe_dump_hlds(!.HLDS, 117, "closure_analysis", !DumpInfo, !IO),
+    maybe_exception_analysis(Verbose, Stats, !HLDS, !IO),
+    maybe_dump_hlds(!.HLDS, 118, "exception_analysis", !DumpInfo, !IO),
+    maybe_termination(Verbose, Stats, !HLDS, !IO),
+    maybe_dump_hlds(!.HLDS, 120, "termination", !DumpInfo, !IO),
+    maybe_termination2(Verbose, Stats, !HLDS, !IO),
+    maybe_dump_hlds(!.HLDS, 121, "termination_2", !DumpInfo, !IO),
+    maybe_unused_args(Verbose, Stats, !HLDS, !IO),
+    maybe_dump_hlds(!.HLDS, 165, "unused_args", !DumpInfo, !IO),
+    maybe_analyse_trail_usage(Verbose, Stats, !HLDS, !IO),
+    maybe_dump_hlds(!.HLDS, 167, "trail_usage", !DumpInfo, !IO),
+
+    module_info_get_analysis_info(!.HLDS, AnalysisInfo0),
+    module_info_get_all_deps(!.HLDS, ImportedModules),
+    ModuleId = module_name_to_module_id(ModuleName),
+    ImportedModuleIds = set.map(module_name_to_module_id,
+        ImportedModules),
+    analysis__write_analysis_files(mmc, ModuleId, ImportedModuleIds,
+        AnalysisInfo0, AnalysisInfo, !IO),
+    module_info_set_analysis_info(AnalysisInfo, !HLDS).
+
 :- pred frontend_pass_by_phases(module_info::in, module_info::out,
     bool::out, dump_info::in, dump_info::out, io::di, io::uo) is det.
 
@@ -3647,10 +3681,13 @@
     globals__lookup_bool_option(Globals, intermod_unused_args, Intermod),
     globals__lookup_bool_option(Globals, optimize_unused_args, Optimize),
     globals__lookup_bool_option(Globals, warn_unused_args, Warn),
+    globals__lookup_bool_option(Globals, intermodule_analysis,
+        IntermodAnalysis),
     (
         ( Optimize = yes
         ; Warn = yes
         ; Intermod = yes
+        ; IntermodAnalysis = yes
         )
     ->
         maybe_write_string(Verbose, "% Finding unused arguments ...\n", !IO),
Index: compiler/options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/options.m,v
retrieving revision 1.492
diff -u -r1.492 options.m
--- compiler/options.m	30 Jan 2006 00:41:32 -0000	1.492
+++ compiler/options.m	1 Feb 2006 03:42:32 -0000
@@ -139,6 +139,7 @@
     ;       debug_make
     ;       debug_closure
     ;       debug_trail_usage
+    ;       debug_intermodule_analysis
 
     % Output options
     ;       make_short_interface
@@ -146,6 +147,7 @@
     ;       make_private_interface
     ;       make_optimization_interface
     ;       make_transitive_opt_interface
+    ;       make_analysis_registry
     ;       generate_source_file_mapping
     ;       generate_dependency_file
     ;       generate_dependencies
@@ -456,12 +458,13 @@
     ;       opt_level_number
     ;       opt_space                   % Default is to optimize time.
     ;       intermodule_optimization
-    ;       intermodule_analysis
     ;       read_opt_files_transitively
     ;       automatic_intermodule_optimization
     ;       use_opt_files
     ;       use_trans_opt_files
     ;       transitive_optimization
+    ;       intermodule_analysis
+    ;       max_reanalysis_passes
 
     %   - HLDS
     ;       allow_inlining
@@ -885,7 +888,8 @@
     debug_stack_opt                     -   int(-1),
     debug_make                          -   bool(no),
     debug_closure                       -   bool(no),
-    debug_trail_usage                   -   bool(no)
+    debug_trail_usage                   -   bool(no),
+    debug_intermodule_analysis          -   bool(no)
 ]).
 option_defaults_2(output_option, [
     % Output Options (mutually exclusive)
@@ -898,6 +902,7 @@
     make_private_interface              -   bool(no),
     make_optimization_interface         -   bool(no),
     make_transitive_opt_interface       -   bool(no),
+    make_analysis_registry              -   bool(no),
     convert_to_mercury                  -   bool(no),
     typecheck_only                      -   bool(no),
     errorcheck_only                     -   bool(no),
@@ -1139,12 +1144,13 @@
     opt_level_number                    -   int(-2),
     opt_space                           -   special,
     intermodule_optimization            -   bool(no),
-    intermodule_analysis                -   bool(no),
     read_opt_files_transitively         -   bool(yes),
     automatic_intermodule_optimization  -   bool(yes),
     use_opt_files                       -   bool(no),
     use_trans_opt_files                 -   bool(no),
     transitive_optimization             -   bool(no),
+    intermodule_analysis                -   bool(no),
+    max_reanalysis_passes               -   int(0),
     check_termination                   -   bool(no),
     verbose_check_termination           -   bool(no),
     termination                         -   bool(no),
@@ -1591,6 +1597,7 @@
 long_option("debug-make",           debug_make).
 long_option("debug-closure",        debug_closure).
 long_option("debug-trail-usage",    debug_trail_usage).
+long_option("debug-intermodule-analysis",   debug_intermodule_analysis).
 
 % output options (mutually exclusive)
 long_option("generate-source-file-mapping",
@@ -1612,6 +1619,8 @@
 long_option("make-transitive-optimisation-interface",
                     make_transitive_opt_interface).
 long_option("make-trans-opt",       make_transitive_opt_interface).
+long_option("make-analysis-registry",   make_analysis_registry).
+long_option("make-analysis",        make_analysis_registry).
 long_option("convert-to-mercury",   convert_to_mercury).
 long_option("convert-to-Mercury",   convert_to_mercury).
 long_option("pretty-print",         convert_to_mercury).
@@ -1835,7 +1844,6 @@
 long_option("intermod-opt",        intermodule_optimization).
 long_option("intermodule-optimization", intermodule_optimization).
 long_option("intermodule-optimisation", intermodule_optimization).
-long_option("intermodule-analysis", intermodule_analysis).
 long_option("read-opt-files-transitively", read_opt_files_transitively).
 long_option("automatic-intermodule-optimization",
                     automatic_intermodule_optimization).
@@ -1848,6 +1856,8 @@
 long_option("transitive-intermodule-optimisation",
                     transitive_optimization).
 long_option("trans-intermod-opt",   transitive_optimization).
+long_option("intermodule-analysis", intermodule_analysis).
+long_option("max-reanalysis-passes",    max_reanalysis_passes).
 
 % HLDS->HLDS optimizations
 long_option("inlining",             inlining).
@@ -2915,6 +2925,9 @@
 %       "\tOutput detailed debugging traces of the closure analysis."
         "--debug-trail-usage",
         "\tOutput detailed debugging traces of the `--analyse-trail-usage'",
+        "\toption.",
+        "--debug-intermodule-analysis",
+        "\tOutput detailed debugging traces of the `--intermodule-analysis'",
         "\toption."
     ]).
 
@@ -2964,6 +2977,10 @@
         "\tOutput transitive optimization information",
         "\tinto the `<module>.trans_opt' file.",
         "\tThis option should only be used by mmake.",
+        "--make-analysis",
+        "--make-analysis-registry",
+        "\tOutput analysis information into the `<module>.analysis' file.",
+        "\tThis option should only be used by mmake.",
         "-P, --convert-to-mercury",
         "\tConvert to Mercury. Output to file `<module>.ugly'",
         "\tThis option acts as a Mercury ugly-printer.",
@@ -3842,7 +3859,11 @@
         "--intermodule-analysis",
         "\tPerform analyses such as termination analysis and",
         "\tunused argument elimination across module boundaries.",
-        "\tThis option is not yet fully implemented."
+        "\tThis option is not yet fully implemented.",
+        "--max-reanalysis-passes <n>",
+        "\tThe maximum number of times to repeat analyses of",
+        "\tsuboptimal modules with `--intermodule-analyses'",
+        "\t(default: 0)."
     ]).
 
 :- pred options_help_hlds_hlds_optimization(io::di, io::uo) is det.
Index: compiler/trailing_analysis.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/trailing_analysis.m,v
retrieving revision 1.5
diff -u -r1.5 trailing_analysis.m
--- compiler/trailing_analysis.m	25 Jan 2006 03:27:36 -0000	1.5
+++ compiler/trailing_analysis.m	1 Feb 2006 04:45:24 -0000
@@ -203,9 +203,10 @@
     %
     % Record the analysis results for the intermodule analysis
     %
-    globals__io_lookup_bool_option(intermodule_analysis, Intermod, !IO),
+    globals__io_lookup_bool_option(make_analysis_registry,
+        MakeAnalysisRegistry, !IO),
     (
-        Intermod = yes,
+        MakeAnalysisRegistry = yes,
         (
             MaybeAnalysisStatus = yes(AnalysisStatus),
             record_trailing_analysis_results(TrailingStatus, AnalysisStatus,
@@ -215,7 +216,7 @@
             unexpected(this_file, "process_scc: no analysis status")
         )
     ;
-        Intermod = no
+        MakeAnalysisRegistry = no
     ),
     (
         Pass1Only = no,
@@ -1108,21 +1109,33 @@
     Call = any_call,
     analysis.lookup_best_result(ModuleId, FuncId, Call,
         MaybeBestStatus, !AnalysisInfo, !IO),
+    globals__io_lookup_bool_option(make_analysis_registry,
+        MakeAnalysisRegistry, !IO),
     (
         MaybeBestStatus = yes({BestCall, trailing_analysis_answer(Result),
             AnalysisStatus}),
-        record_dependencies(ModuleId, FuncId, BestCall,
-            ModuleInfo, CallerSCC, !AnalysisInfo)
+        (
+            MakeAnalysisRegistry = yes,
+            record_dependencies(ModuleId, FuncId, BestCall,
+                ModuleInfo, CallerSCC, !AnalysisInfo)
+        ;
+            MakeAnalysisRegistry = no
+        )
     ;
         MaybeBestStatus = no,
         % If we do not have any information about the callee procedure
         % then assume that it modifies the trail.
         top(Call) = trailing_analysis_answer(Result),
         AnalysisStatus = suboptimal,
-        analysis.record_request(analysis_name, ModuleId, FuncId, Call,
-            !AnalysisInfo),
-        record_dependencies(ModuleId, FuncId, Call,
-            ModuleInfo, CallerSCC, !AnalysisInfo)
+        (
+            MakeAnalysisRegistry = yes,
+            analysis.record_request(analysis_name, ModuleId, FuncId, Call,
+                !AnalysisInfo),
+            record_dependencies(ModuleId, FuncId, Call,
+                ModuleInfo, CallerSCC, !AnalysisInfo)
+        ;
+            MakeAnalysisRegistry = no
+        )
     ).
 
     % XXX if the procedures in CallerSCC definitely come from the
Index: compiler/unused_args.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/unused_args.m,v
retrieving revision 1.117
diff -u -r1.117 unused_args.m
--- compiler/unused_args.m	25 Jan 2006 03:27:36 -0000	1.117
+++ compiler/unused_args.m	1 Feb 2006 04:56:34 -0000
@@ -270,15 +270,16 @@
     ;
         MaybeOptFile = no
     ),
-    globals__io_lookup_bool_option(intermodule_analysis, Intermod, !IO),
+    globals__io_lookup_bool_option(make_analysis_registry,
+        MakeAnalysisRegistry, !IO),
     (
-        Intermod = yes,
+        MakeAnalysisRegistry = yes,
         module_info_get_analysis_info(!.ModuleInfo, AnalysisInfo0),
         list__foldl2(record_intermod_dependencies(!.ModuleInfo),
             PredProcs, AnalysisInfo0, AnalysisInfo, !IO),
         module_info_set_analysis_info(AnalysisInfo, !ModuleInfo)
     ;
-        Intermod = no
+        MakeAnalysisRegistry = no
     ),
     globals__io_lookup_bool_option(optimize_unused_args, DoFixup, !IO),
     (
@@ -434,8 +435,16 @@
             ;
                 MaybeBestResult = no,
                 % XXX makes too many requests
-                analysis.record_request(analysis_name, PredModuleId, 
-                    FuncId, Call, AnalysisInfo1, AnalysisInfo)
+                globals__io_lookup_bool_option(make_analysis_registry,
+                    MakeAnalysisRegistry, !IO),
+                (
+                    MakeAnalysisRegistry = yes,
+                    analysis.record_request(analysis_name, PredModuleId, 
+                        FuncId, Call, AnalysisInfo1, AnalysisInfo)
+                ;
+                    MakeAnalysisRegistry = no,
+                    AnalysisInfo = AnalysisInfo1
+                )
             ),
             module_info_set_analysis_info(AnalysisInfo, !ModuleInfo)
         ;
@@ -987,7 +996,12 @@
         % XXX: optimal?  If we know some output arguments are not going to be
         % used by the caller then more input arguments could be deduced to be
         % unused.  This analysis doesn't handle that yet.
-        ( procedure_is_exported(!.ModuleInfo, OrigPredInfo, ProcId) ->
+        globals__io_lookup_bool_option(make_analysis_registry,
+            MakeAnalysisRegistry, !IO),
+        ( 
+            MakeAnalysisRegistry = yes,
+            procedure_is_exported(!.ModuleInfo, OrigPredInfo, ProcId)
+        ->
             analysis__record_result(ModuleId, FuncId, Call, Answer, optimal,
                 AnalysisInfo1, AnalysisInfo)
         ;
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.466
diff -u -r1.466 user_guide.texi
--- doc/user_guide.texi	27 Jan 2006 05:52:11 -0000	1.466
+++ doc/user_guide.texi	1 Feb 2006 03:15:41 -0000
@@ -5464,6 +5464,11 @@
 @c @findex --debug-closures
 @c Output detailed debugging traces of the `--analyse-closures' option.
 
+ at sp 1
+ at item --debug-intermodule-analysis
+ at findex --debug-intermodule-analysis
+Output detailed debugging traces of the `--intermodule-analysis' option.
+
 @end table
 
 @node Output options
@@ -6900,6 +6905,12 @@
 unused argument elimination across module boundaries.
 This option is not yet fully implemented.
 
+ at item --max-reanalysis-passes <n>
+ at findex --max-reanalysis-passes
+The maximum number of times to repeat analyses of suboptimal modules with
+ at samp{--intermodule-analyses} (default: 0).  This option only works with
+ at samp{mmc --make}.
+
 @end table
 
 @node High-level (HLDS -> HLDS) optimization options
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list