[m-rev.] for review: analysis framework and libraries

Peter Wang wangp at students.cs.mu.OZ.AU
Fri Feb 10 15:23:26 AEDT 2006


Estimated hours taken: 25
Branches: main

This patch mainly improves the handling of libraries with the intermodule
analysis framework.  `.analysis' files can now be installed into library
directories and used when analysing local modules.

analysis/analysis.m:
analysis/analysis.file.m:
compiler/mmc_analysis.m:
	Separate the `module_id_to_file_name' method of the `compiler'
	typeclass into `module_id_to_read_file_name' and
	`module_id_to_write_file_name'.  Add `module_is_local' method.

	Change the calls to `module_id_to_file_name' appropriately for the
	context.  This allows us to find the `.analysis' files of library
	modules.

	Only write results, IMDG and request files for local modules.

	Force `.analysis' files of the currently-analysed module to be written
	out, even if it would be empty.  This avoids us trying to reanalyse the
	module later.

compiler/options.m:
	Add internal compiler option `--local-module-id'.

compiler/make.dependencies.m:
	Add `make_local_module_id_options' to build a list of
	`--local-module-id' options.

compiler/make.module_target.m:
	Add predicate `make_module_target_extra_options' so we can pass the
	`--local-module-id' options.

compiler/make.program_target.m:
	Analyse modules in bottom up order, according to the module dependency
	graph.  The current analyses don't support non-default call patterns,
	so this should reduce the number of analysis passes to get (close to)
	to a fixpoint.

	Pass `--local-module-id' options when building analysis files, so the
	analysis framework knows which modules are local.

	Install `.analysis' files when installing libraries.

compiler/modules.m:
	Make `.analysis', `.analysis_date', `.imdg' and `.request' files
	architecture- or grade-specified so they go into grade directories
	when `--use-grade-subdirs' is used.

	Search for `.analysis' files in the same directories as `.opt' and
	`.trans_opt' files.

	Export predicate `add_module_relations' to help build module dependency
	graphs.

compiler/mercury_compile.m:
	Fix a bug where the unused argument optimisation pass was always being
	run if `--intermodule-analysis' was enabled.


Index: analysis/analysis.file.m
===================================================================
RCS file: /home/mercury1/repository/mercury/analysis/analysis.file.m,v
retrieving revision 1.4
diff -u -r1.4 analysis.file.m
--- analysis/analysis.file.m	6 Feb 2006 05:39:40 -0000	1.4
+++ analysis/analysis.file.m	10 Feb 2006 02:57:54 -0000
@@ -87,8 +87,20 @@
 %-----------------------------------------------------------------------------%
 
 read_module_overall_status(Compiler, ModuleId, MaybeModuleStatus, !IO) :-
-    module_id_to_file_name(Compiler, ModuleId, analysis_registry_suffix,
-	AnalysisFileName, !IO),
+    module_id_to_read_file_name(Compiler, ModuleId, analysis_registry_suffix,
+	MaybeAnalysisFileName, !IO),
+    (
+	MaybeAnalysisFileName = ok(AnalysisFileName),
+	read_module_overall_status_2(AnalysisFileName, MaybeModuleStatus, !IO)
+    ;
+	MaybeAnalysisFileName = error(_),
+	MaybeModuleStatus = no
+    ).
+
+:- pred read_module_overall_status_2(string::in, maybe(analysis_status)::out,
+    io::di, io::uo) is det.
+
+read_module_overall_status_2(AnalysisFileName, MaybeModuleStatus, !IO) :-
     io__open_input(AnalysisFileName, OpenResult, !IO),
     (
 	OpenResult = ok(Stream),
@@ -331,11 +343,18 @@
 read_analysis_file(Compiler, ModuleId, Suffix,
 		ReadHeader, DefaultHeader, Header,
 		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).
+	module_id_to_read_file_name(Compiler, ModuleId,
+		Suffix, MaybeAnalysisFileName, !IO),
+	(
+		MaybeAnalysisFileName = ok(AnalysisFileName),
+		read_analysis_file(AnalysisFileName,
+			ReadHeader, DefaultHeader, Header,
+			ParseEntry, ModuleResults0, ModuleResults, !IO)
+	;
+		MaybeAnalysisFileName = error(_),
+		Header = DefaultHeader,
+		ModuleResults = ModuleResults0
+	).
 
 :- pred read_analysis_file(string::in,
 		read_analysis_header(Header)::in(read_analysis_header),
@@ -443,7 +462,8 @@
     analysis_status_to_string(Status, String).
 
 write_module_analysis_requests(Info, ModuleId, ModuleRequests, !IO) :-
-	module_id_to_file_name(Info ^ compiler, ModuleId, request_suffix,
+	Compiler = Info ^ compiler,
+	module_id_to_write_file_name(Compiler, ModuleId, request_suffix,
 		AnalysisFileName, !IO),
 	debug_msg((pred(!.IO::di, !:IO::uo) is det :-
 		io.print("Writing module analysis requests to ", !IO),
@@ -469,7 +489,7 @@
 				io__set_output_stream(AppendStream,
 					OldOutputStream, !IO),
 				write_analysis_entries(
-					write_request_entry(Info ^ compiler),
+					write_request_entry(Compiler),
 					ModuleRequests, !IO),
 				io__set_output_stream(OldOutputStream, _, !IO),
 				io__close_output(AppendStream, !IO),
@@ -484,9 +504,8 @@
 		Appended = no
 	),
 	( Appended = no ->
-		write_analysis_file(Info ^ compiler, ModuleId, request_suffix,
-			nop,
-			write_request_entry(Info ^ compiler),
+		write_analysis_file(AnalysisFileName,
+			nop, write_request_entry(Compiler),
 			ModuleRequests, !IO)
 	;
 		true
@@ -576,10 +595,19 @@
 	write_entry(T)::in(write_entry), module_analysis_map(T)::in,
 	io__state::di, io__state::uo) is det <= compiler(Compiler).
 
-write_analysis_file(Compiler, ModuleId, Suffix, WriteHeader,
-		WriteEntry, ModuleResults, !IO) :-
-	module_id_to_file_name(Compiler, ModuleId,
-		Suffix, AnalysisFileName, !IO),
+write_analysis_file(Compiler, ModuleId, Suffix, WriteHeader, WriteEntry,
+		ModuleResults, !IO) :-
+	module_id_to_write_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),
@@ -615,7 +643,7 @@
 	    ), ModuleResults, !IO).
 
 empty_request_file(Info, ModuleId, !IO) :-
-	module_id_to_file_name(Info ^ compiler, ModuleId, request_suffix,
+	module_id_to_write_file_name(Info ^ compiler, ModuleId, request_suffix,
 		RequestFileName, !IO),
 	debug_msg((pred(!.IO::di, !:IO::uo) is det :-
 		io.print("Removing request file ", !IO),
Index: analysis/analysis.m
===================================================================
RCS file: /home/mercury1/repository/mercury/analysis/analysis.m,v
retrieving revision 1.4
diff -u -r1.4 analysis.m
--- analysis/analysis.m	6 Feb 2006 05:39:40 -0000	1.4
+++ analysis/analysis.m	10 Feb 2006 03:15:02 -0000
@@ -36,9 +36,22 @@
 	% Describe the analyses which can be performed by a compiler.
 	func analyses(Compiler, analysis_name) = analysis_type is semidet,
 
-	% module_id_to_file_name(Compiler, ModuleId, Ext, FileName)
-	pred module_id_to_file_name(Compiler::in, module_id::in,
-		string::in, string::out, io__state::di, io__state::uo) is det
+	% module_id_to_read_file_name(Compiler, ModuleId, Ext, FileName)
+	pred module_id_to_read_file_name(Compiler::in, module_id::in,
+		string::in, maybe_error(string)::out, io::di, io::uo) is det,
+
+	% module_id_to_write_file_name(Compiler, ModuleId, Ext, FileName)
+	pred module_id_to_write_file_name(Compiler::in, module_id::in,
+		string::in, string::out, io::di, io::uo) is det,
+
+	% module_is_local(Compiler, ModuleId, IsLocal, !IO)
+	%
+	% IsLocal is `yes' if the module is not a "library" module, i.e. we are
+	% able to reanalyse the module, not just use results that already
+	% exist.
+	% 
+	pred module_is_local(Compiler::in, module_id::in, bool::out,
+	    io::di, io::uo) is det
 ].
 
 :- type module_id == string.
@@ -911,7 +924,10 @@
     (if NewResults = !.Info ^ new_analysis_results ^ elem(ModuleId) then
 	ModuleStatus = lub_result_statuses(NewResults)
     else
-	ModuleStatus = optimal
+	ModuleStatus = optimal,
+	% Force an `.analysis' file to be written out for this module,
+	% even though there are no results recorded for it.
+	!:Info = !.Info ^ new_analysis_results ^ elem(ModuleId) := map.init
     ),
 
     update_analysis_registry(!Info, !IO),
@@ -931,11 +947,11 @@
     % Write the results for all the modules we know of.  For the
     % module being compiled, the analysis results may have changed.
     % For other modules, their overall statuses may have changed.
-    map.foldl(write_analysis_files_2(!.Info),
+    write_local_modules(!.Info, write_module_analysis_results,
 	!.Info ^ old_analysis_results, !IO),
 
     % Write the requests for the imported modules.
-    map.foldl(write_module_analysis_requests(!.Info),
+    write_local_modules(!.Info, write_module_analysis_requests,
 	!.Info ^ analysis_requests, !IO),
 
     % Remove the requests for the current module since we (should have)
@@ -943,11 +959,12 @@
     empty_request_file(!.Info, ModuleId, !IO),
 
     % Write the intermodule dependency graphs.
-    map.foldl(write_module_imdg(!.Info), !.Info ^ old_imdg, !IO),
+    write_local_modules(!.Info, write_module_imdg,
+	!.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",
+    module_id_to_write_file_name(Compiler, ModuleId, ".analysis_date",
 	TimestampFileName, !IO),
     io.open_output(TimestampFileName, Result, !IO),
     (
@@ -959,10 +976,38 @@
 	error(io.error_message(IOError))
     ).
 
-:- pred write_analysis_files_2(analysis_info::in, module_id::in,
+:- type write_module_analysis_map(T) ==
+    (pred(analysis_info, module_id, module_analysis_map(T), io, io)).
+:- mode write_module_analysis_map == in(pred(in, in, in, di, uo) is det).
+
+:- pred write_local_modules(analysis_info::in,
+    write_module_analysis_map(T)::write_module_analysis_map,
+    analysis_map(T)::in, io::di, io::uo) is det.
+:- pred write_local_modules_2(analysis_info::in,
+    write_module_analysis_map(T)::write_module_analysis_map,
+    module_id::in, module_analysis_map(T)::in, io::di, io::uo) is det.
+
+write_local_modules(Info, Write, AnalysisMap, !IO) :-
+    map.foldl(write_local_modules_2(Info, Write), AnalysisMap, !IO).
+
+write_local_modules_2(Info, Write, ModuleId, ModuleResults, !IO) :-
+    module_is_local(Info ^ compiler, ModuleId, IsLocal, !IO),
+    (
+	IsLocal = yes,
+	Write(Info, ModuleId, ModuleResults, !IO)
+    ;
+	IsLocal = no,
+	debug_msg((pred(!.IO::di, !:IO::uo) is det :-
+	    io.write_string("Not writing file for non-local module ", !IO),
+	    io.write_string(ModuleId, !IO),
+	    io.nl(!IO)
+	), !IO)
+    ).
+
+:- pred write_module_analysis_results(analysis_info::in, module_id::in,
 	module_analysis_map(analysis_result)::in, io::di, io::uo) is det.
 
-write_analysis_files_2(Info, ModuleId, ModuleResults, !IO) :-
+write_module_analysis_results(Info, ModuleId, ModuleResults, !IO) :-
     ModuleStatus = Info ^ module_statuses ^ det_elem(ModuleId),
     write_module_analysis_results(Info, ModuleId,
 	ModuleStatus, ModuleResults, !IO).
Index: compiler/make.dependencies.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/make.dependencies.m,v
retrieving revision 1.24
diff -u -r1.24 make.dependencies.m
--- compiler/make.dependencies.m	6 Feb 2006 05:39:41 -0000	1.24
+++ compiler/make.dependencies.m	10 Feb 2006 00:03:59 -0000
@@ -63,6 +63,16 @@
 
 %-----------------------------------------------------------------------------%
 
+    % Find all modules in the current directory which are
+    % reachable (by import) from the given module.
+    % Return a list of `--local-module-id' options suitable for the
+    % command line.
+    %
+:- pred make_local_module_id_options(module_name::in, bool::out,
+    list(string)::out, make_info::in, make_info::out, io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
+
 :- pred dependency_status(dependency_file::in, dependency_status::out,
     make_info::in, make_info::out, io::di, io::uo) is det.
 
@@ -106,6 +116,9 @@
 
 :- implementation.
 
+:- import_module transform_hlds.
+:- import_module transform_hlds__mmc_analysis.
+
 %-----------------------------------------------------------------------------%
 
 :- type deps_result(T) == pair(bool, set(T)).
@@ -887,6 +900,19 @@
 
 %-----------------------------------------------------------------------------%
 
+make_local_module_id_options(ModuleName, Success, Options, !Info, !IO) :-
+    find_reachable_local_modules(ModuleName, Success, LocalModules,
+        !Info, !IO),
+    set.fold(make_local_module_id_option, LocalModules, [], Options).
+
+:- pred make_local_module_id_option(module_name::in, list(string)::in,
+    list(string)::out) is det.
+
+make_local_module_id_option(ModuleName, Opts,
+    ["--local-module-id", module_name_to_module_id(ModuleName) | Opts]).
+
+%-----------------------------------------------------------------------------%
+
 :- pred check_dependencies_debug_unbuilt(file_name::in,
     assoc_list(dependency_file, dependency_status)::in,
     io::di, io::uo) is det.
Index: compiler/make.module_target.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/make.module_target.m,v
retrieving revision 1.36
diff -u -r1.36 make.module_target.m
--- compiler/make.module_target.m	6 Feb 2006 05:39:42 -0000	1.36
+++ compiler/make.module_target.m	10 Feb 2006 00:24:54 -0000
@@ -26,6 +26,15 @@
 :- pred make_module_target(dependency_file::in, bool::out,
     make_info::in, make_info::out, io::di, io::uo) is det.
 
+    % make_module_target_extra_options(ExtraOpts, Target, Success, Info0, Info)
+    %
+    % Make a target corresponding to a single module, with extra command line
+    % options.
+    %
+:- pred make_module_target_extra_options(list(string)::in,
+    dependency_file::in, bool::out,
+    make_info::in, make_info::out, io::di, io::uo) is det.
+
     % record_made_target(Target, Task, MakeSucceeded)
     %
     % Record whether building a target succeeded or not.
@@ -75,10 +84,15 @@
         !Info, !IO) :-
     make_module_target(TargetFile, Succeeded2, !Info, !IO).
 
-make_module_target(file(_, _) @ Dep, Succeeded, !Info, !IO) :-
+make_module_target(DepFile, Succeeded, !Info, !IO) :-
+    make_module_target_extra_options([], DepFile, Succeeded, !Info, !IO).
+
+make_module_target_extra_options(_ExtraOptions, file(_, _) @ Dep,
+        Succeeded, !Info, !IO) :-
     dependency_status(Dep, Status, !Info, !IO),
     Succeeded = ( Status = error -> no ; yes ).
-make_module_target(target(TargetFile) @ Dep, Succeeded, !Info, !IO) :-
+make_module_target_extra_options(ExtraOptions, target(TargetFile) @ Dep,
+        Succeeded, !Info, !IO) :-
     dependency_status(Dep, Status, !Info, !IO),
     (
         Status = not_considered,
@@ -100,7 +114,7 @@
                 CompilationTask = process_module(_) - _,
                 Imports ^ source_file_module_name \= ModuleName
             ->
-                make_module_target(
+                make_module_target_extra_options(ExtraOptions,
                     target(Imports ^ source_file_module_name - FileType),
                     Succeeded, !Info, !IO)
             ;
@@ -167,8 +181,8 @@
                         set__delete(!.Info ^ command_line_targets,
                             ModuleName - module_target(FileType)),
                     build_target(CompilationTask, TargetFile, Imports,
-                        TouchedTargetFiles, TouchedFiles, Succeeded,
-                        !Info, !IO)
+                        TouchedTargetFiles, TouchedFiles, ExtraOptions,
+                        Succeeded, !Info, !IO)
                 ;
                     DepsResult = up_to_date,
                     maybe_warn_up_to_date_target(
@@ -286,11 +300,11 @@
 
 :- pred build_target(compilation_task_result::in, target_file::in,
     module_imports::in, list(target_file)::in, list(file_name)::in,
-    bool::out, make_info::in, make_info::out,
+    list(string)::in, bool::out, make_info::in, make_info::out,
     io::di, io::uo) is det.
 
 build_target(CompilationTask, TargetFile, Imports, TouchedTargetFiles,
-        TouchedFiles, Succeeded, !Info, !IO) :-
+        TouchedFiles, ExtraOptions, Succeeded, !Info, !IO) :-
     maybe_make_target_message(TargetFile, !IO),
     TargetFile = ModuleName - _FileType,
     CompilationTask = Task - TaskOptions,
@@ -322,8 +336,8 @@
         ),
     build_with_check_for_interrupt(
         build_with_module_options_and_output_redirect(ModuleName,
-        TaskOptions,
-        build_target_2(ModuleName, Task, MaybeArgFileName, Imports)),
+            ExtraOptions ++ TaskOptions,
+            build_target_2(ModuleName, Task, MaybeArgFileName, Imports)),
         Cleanup, Succeeded, !Info, !IO),
     record_made_target_2(Succeeded, TargetFile, TouchedTargetFiles,
         TouchedFiles, !Info, !IO).
Index: compiler/make.program_target.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/make.program_target.m,v
retrieving revision 1.40
diff -u -r1.40 make.program_target.m
--- compiler/make.program_target.m	7 Feb 2006 00:06:20 -0000	1.40
+++ compiler/make.program_target.m	10 Feb 2006 04:17:19 -0000
@@ -46,6 +46,9 @@
 :- import_module transform_hlds.
 :- import_module transform_hlds.mmc_analysis.
 
+:- import_module relation.
+:- import_module svrelation.
+
 %-----------------------------------------------------------------------------%
 
 make_linked_target(MainModuleName - FileType, Succeeded, !Info, !IO) :-
@@ -598,43 +601,93 @@
 
 build_analysis_files(MainModuleName, AllModules, Succeeded0, Succeeded,
         !Info, !IO) :-
-    get_target_modules(analysis_registry, AllModules, TargetModules,
+    get_target_modules(analysis_registry, AllModules, TargetModules0,
         !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_analysis_files(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_analysis_files(MainModuleName, AllModules,
-                Succeeded0, Succeeded, !Info, !IO)
+        reverse_ordered_modules(!.Info ^ module_dependencies,
+            TargetModules0, TargetModules),
+        make_local_module_id_options(MainModuleName, Succeeded1,
+            LocalModulesOpts, !Info, !IO),
+        (
+            Succeeded1 = yes,
+            build_analysis_files_2(MainModuleName, TargetModules, 
+                LocalModulesOpts, Succeeded0, Succeeded, !Info, !IO)
         ;
-            Succeeded = Succeeded0 `and` Succeeded1
+            Succeeded1 = no,
+            Succeeded = no
         )
     ).
 
+:- pred build_analysis_files_2(module_name::in, list(module_name)::in,
+    list(string)::in, bool::in, bool::out, make_info::in, make_info::out,
+    io::di, io::uo) is det.
+
+build_analysis_files_2(MainModuleName, TargetModules, LocalModulesOpts,
+        Succeeded0, Succeeded, !Info, !IO) :-
+    globals__io_lookup_bool_option(keep_going, KeepGoing, !IO),
+    foldl2_maybe_stop_at_error(KeepGoing,
+        make_module_target_extra_options(LocalModulesOpts),
+        make_dependency_list(TargetModules, analysis_registry),
+        Succeeded1, !Info, !IO),
+    % Maybe we should have an option to reanalyse cliques before moving 
+    % upwards in the dependency graph?
+
+    % 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_analysis_files_2(MainModuleName, TargetModules, LocalModulesOpts,
+            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_analysis_files_2(MainModuleName, TargetModules, LocalModulesOpts,
+            Succeeded0, Succeeded, !Info, !IO)
+    ;
+        Succeeded = Succeeded0 `and` Succeeded1
+    ).
+
+    % Return a list of modules in reverse order of their dependencies, i.e.
+    % the list is the module dependency graph from bottom-up.  Mutually
+    % dependent modules (modules which form a clique in the dependency graph)
+    % are returned adjacent in the list in arbitrary order.
+    %
+:- pred reverse_ordered_modules(map(module_name, maybe(module_imports))::in,
+    list(module_name)::in, list(module_name)::out) is det.
+
+reverse_ordered_modules(ModuleDeps, Modules0, Modules) :-
+    list__foldl2(add_module_relations(lookup_module_imports(ModuleDeps)),
+        Modules0, relation__init, _IntRel, relation__init, ImplRel),
+    relation__atsort(ImplRel, Order0),
+    list__reverse(Order0, Order1),
+    list__map(set__to_sorted_list, Order1, Order2),
+    list__condense(Order2, Modules).
+
+:- func lookup_module_imports(map(module_name, maybe(module_imports)),
+    module_name) = module_imports.
+
+lookup_module_imports(ModuleDeps, ModuleName) = ModuleImports :-
+    map__lookup(ModuleDeps, ModuleName, MaybeModuleImports),
+    (
+        MaybeModuleImports = yes(ModuleImports)
+    ;
+        MaybeModuleImports = no,
+        unexpected(this_file, "lookup_module_imports")
+    ).
+
 :- pred modules_needing_reanalysis(bool::in, list(module_name)::in,
     list(module_name)::out, list(module_name)::out, io::di, io::uo) is det.
 
@@ -939,7 +992,7 @@
         Succeeded = no
     ).
 
-    % Install the `.opt' and `.mih' files for the current grade.
+    % Install the `.opt', `.analysis' and `.mih' files for the current grade.
     %
 :- pred install_grade_ints_and_headers(bool::in, string::in, module_name::in,
     bool::out, make_info::in, make_info::out, io::di, io::uo) is det.
@@ -978,18 +1031,31 @@
             HeaderSucceeded = yes
         ),
 
+        GradeIntDir = LibDir/"ints"/GradeDir,
         globals__io_lookup_bool_option(intermodule_optimization, Intermod,
             !IO),
         (
             Intermod = yes,
-            GradeIntDir = LibDir/"ints"/GradeDir,
             install_subdir_file(LinkSucceeded, GradeIntDir, ModuleName, "opt",
                 OptSucceeded, !IO)
         ;
             Intermod = no,
             OptSucceeded = yes
         ),
-        Succeeded = HeaderSucceeded `and` OptSucceeded
+
+        globals__io_lookup_bool_option(intermodule_analysis, IntermodAnalysis,
+            !IO),
+        (
+            IntermodAnalysis = yes,
+            install_subdir_file(LinkSucceeded, GradeIntDir,
+                ModuleName, "analysis", IntermodAnalysisSucceeded, !IO)
+        ;
+            IntermodAnalysis = no,
+            IntermodAnalysisSucceeded = yes
+        ),
+        
+        Succeeded = HeaderSucceeded `and` OptSucceeded `and`
+            IntermodAnalysisSucceeded
     ;
         MaybeImports = no,
         Succeeded = no
@@ -1092,7 +1158,7 @@
 
     make_install_symlink(GradeIncSubdir, "mih", LinkResult0, !IO),
     list__map_foldl(make_install_symlink(GradeIntsSubdir),
-        ["opt", "trans_opt"], LinkResults, !IO),
+        ["opt", "trans_opt", "analysis"], LinkResults, !IO),
     LinkResult = bool__and_list([LinkResult0 | LinkResults]),
     (
         LinkResult = yes,
@@ -1102,7 +1168,8 @@
         make_directory(GradeIncSubdir/"mihs", Result4, !IO),
         make_directory(GradeIntsSubdir/"opts", Result5, !IO),
         make_directory(GradeIntsSubdir/"trans_opts", Result6, !IO),
-        Results = [Result4, Result5, Result6 | Results0]
+        make_directory(GradeIntsSubdir/"analysiss", Result7, !IO),
+        Results = [Result4, Result5, Result6, Result7 | Results0]
     ),
     print_mkdir_errors(Results, Result, !IO).
 
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.375
diff -u -r1.375 mercury_compile.m
--- compiler/mercury_compile.m	6 Feb 2006 05:39:42 -0000	1.375
+++ compiler/mercury_compile.m	9 Feb 2006 00:13:42 -0000
@@ -3678,13 +3678,10 @@
     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/mmc_analysis.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mmc_analysis.m,v
retrieving revision 1.11
diff -u -r1.11 mmc_analysis.m
--- compiler/mmc_analysis.m	1 Feb 2006 04:02:46 -0000	1.11
+++ compiler/mmc_analysis.m	10 Feb 2006 02:49:12 -0000
@@ -43,7 +43,10 @@
 
 :- implementation.
 
+:- import_module libs.globals.
+:- import_module libs.options.
 :- import_module parse_tree.modules.
+:- import_module parse_tree.prog_io.
 :- import_module parse_tree.prog_out.
 :- import_module parse_tree.prog_util.
 :- import_module transform_hlds.exception_analysis.
@@ -51,8 +54,10 @@
 :- import_module transform_hlds.unused_args.
 
 :- import_module bool.
+:- import_module list.
 :- import_module std_util.
 :- import_module string.
+:- import_module io.
 
 %-----------------------------------------------------------------------------%
 
@@ -74,11 +79,39 @@
             unit1 : unit(unused_args_call),
             unit1 : unit(unused_args_answer)),
 
-    module_id_to_file_name(mmc, ModuleId, Ext, FileName) -->
-        module_name_to_file_name(module_id_to_module_name(ModuleId),
-            Ext, yes, FileName)
+    module_id_to_read_file_name(mmc, ModuleId, Ext, FileName, !IO) :-
+        mmc_module_id_to_read_file_name(ModuleId, Ext, FileName, !IO),
+
+    module_id_to_write_file_name(mmc, ModuleId, Ext, FileName, !IO) :-
+        mmc_module_id_to_write_file_name(ModuleId, Ext, FileName, !IO),
+
+    module_is_local(mmc, ModuleId, IsLocal, !IO) :-
+        mmc_module_is_local(ModuleId, IsLocal, !IO)
 ].
 
+:- pred mmc_module_id_to_read_file_name(module_id::in, string::in,
+    maybe_error(string)::out, io::di, io::uo) is det.
+
+mmc_module_id_to_read_file_name(ModuleId, Ext, MaybeFileName, !IO) :-
+    ModuleName = module_id_to_module_name(ModuleId),
+    modules.module_name_to_search_file_name(ModuleName, Ext, FileName0, !IO),
+    globals.io_lookup_accumulating_option(intermod_directories, Dirs, !IO),
+    search_for_file(Dirs, FileName0, MaybeFileName, !IO).
+
+:- pred mmc_module_id_to_write_file_name(module_id::in, string::in, string::out,
+    io::di, io::uo) is det.
+
+mmc_module_id_to_write_file_name(ModuleId, Ext, FileName, !IO) :-
+    ModuleName = module_id_to_module_name(ModuleId),
+    module_name_to_file_name(ModuleName, Ext, yes, FileName, !IO).
+
+:- pred mmc_module_is_local(module_id::in, bool::out, io::di, io::uo) is det.
+
+mmc_module_is_local(ModuleId, IsLocal, !IO) :-
+    globals__io_lookup_accumulating_option(local_module_id, LocalModuleIds,
+        !IO),
+    IsLocal = (if ModuleId `list.member` LocalModuleIds then yes else no).
+
 module_name_to_module_id(ModuleName) = ModuleId :-
     sym_name_to_string(ModuleName, ModuleId).
 
Index: compiler/modules.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/modules.m,v
retrieving revision 1.371
diff -u -r1.371 modules.m
--- compiler/modules.m	7 Feb 2006 00:06:20 -0000	1.371
+++ compiler/modules.m	10 Feb 2006 04:12:40 -0000
@@ -52,6 +52,7 @@
 :- import_module io.
 :- import_module list.
 :- import_module map.
+:- import_module relation.
 :- import_module set.
 :- import_module std_util.
 
@@ -633,6 +634,20 @@
     %
 :- pred generate_file_dependency_file(file_name::in, io::di, io::uo) is det.
 
+    % add_module_relations(LookupModuleImports, ModuleName,
+    %   !IntDepsRel, !ImplDepsRel)
+    %
+    % Add a module's interface and implementation dependencies to IntDepsRel
+    % and ImplDepsRel respectively.  Dependencies are found using the
+    % LookupModuleImports function.
+    %
+:- pred add_module_relations(lookup_module_imports::lookup_module_imports,
+    module_name::in, relation(module_name)::in, relation(module_name)::out,
+    relation(module_name)::in, relation(module_name)::out) is det.
+
+:- type lookup_module_imports == (func(module_name) = module_imports).
+:- mode lookup_module_imports == in(func(in) = out is det).
+
     % get_dependencies(Items, ImportDeps, UseDeps):
     %
     % Get the list of modules that a list of items (explicitly) depends on.
@@ -803,7 +818,6 @@
 :- import_module getopt_io.
 :- import_module library.
 :- import_module multi_map.
-:- import_module relation.
 :- import_module sparse_bitset.
 :- import_module string.
 :- import_module svmap.
@@ -1152,6 +1166,7 @@
             Search = yes,
             ( Ext = ".opt"
             ; Ext = ".trans_opt"
+            ; Ext = ".analysis"
             )
         )
     ->
@@ -1213,6 +1228,10 @@
 file_is_arch_or_grade_dependent_2(".optdate").
 file_is_arch_or_grade_dependent_2(".trans_opt").
 file_is_arch_or_grade_dependent_2(".trans_opt_date").
+file_is_arch_or_grade_dependent_2(".analysis").
+file_is_arch_or_grade_dependent_2(".analysis_date").
+file_is_arch_or_grade_dependent_2(".imdg").
+file_is_arch_or_grade_dependent_2(".request").
 file_is_arch_or_grade_dependent_2(".mih").
 file_is_arch_or_grade_dependent_2(".c").
 file_is_arch_or_grade_dependent_2(".c_date").
@@ -4321,47 +4340,68 @@
     Deps = deps(_, ModuleImports),
     ModuleError = ModuleImports ^ error,
     ( ModuleError \= fatal_module_errors ->
-        %
-        % Add interface dependencies to the interface deps relation.
-        %
-        % Note that we need to do this both for the interface imports
-        % of this module and for the *implementation* imports of
-        % its ancestors.  This is because if this module is defined
-        % in the implementation section of its parent, then the
-        % interface of this module may depend on things
-        % imported only by its parent's implementation.
-        %
-        % If this module was actually defined in the interface
-        % section of one of its ancestors, then it should only
-        % depend on the interface imports of that ancestor,
-        % so the dependencies added here are in fact more
-        % conservative than they need to be in that case.
-        % However, that should not be a major problem.
-        %
-        ModuleName = ModuleImports ^ module_name,
-        ParentDeps = ModuleImports ^ parent_deps,
-        svrelation__add_element(ModuleName, IntModuleKey, !IntRel),
-        add_int_deps(IntModuleKey, ModuleImports, !IntRel),
-        add_parent_impl_deps_list(DepsMap, IntModuleKey, ParentDeps, !IntRel),
-
-        %
-        % Add implementation dependencies to the impl. deps relation.
-        % (The implementation dependencies are a superset of the
-        % interface dependencies.)
-        %
-        % Note that we need to do this both for the imports
-        % of this module and for the imports of its parents,
-        % because this module may depend on things imported
-        % only by its parents.
-        %
-        svrelation__add_element(ModuleName, ImplModuleKey, !ImplRel),
-        add_impl_deps(ImplModuleKey, ModuleImports, !ImplRel),
-        add_parent_impl_deps_list(DepsMap, ImplModuleKey, ParentDeps, !ImplRel)
+        module_imports_to_deps_rel(ModuleImports,
+            lookup_module_imports(DepsMap), !IntRel, !ImplRel)
     ;
         true
     ),
     deps_list_to_deps_rel(DepsList, DepsMap, !IntRel, !ImplRel).
 
+:- func lookup_module_imports(deps_map, module_name) = module_imports.
+
+lookup_module_imports(DepsMap, ModuleName) = ModuleImports :-
+    map__lookup(DepsMap, ModuleName, deps(_, ModuleImports)).
+
+add_module_relations(LookupModuleImports, ModuleName, !IntRel, !ImplRel) :-
+    ModuleImports = LookupModuleImports(ModuleName),
+    module_imports_to_deps_rel(ModuleImports, LookupModuleImports,
+        !IntRel, !ImplRel).
+
+:- pred module_imports_to_deps_rel(module_imports::in,
+    lookup_module_imports::lookup_module_imports,
+    deps_rel::in, deps_rel::out, deps_rel::in, deps_rel::out) is det.
+
+module_imports_to_deps_rel(ModuleImports, LookupModuleImports,
+        !IntRel, !ImplRel) :-
+    %
+    % Add interface dependencies to the interface deps relation.
+    %
+    % Note that we need to do this both for the interface imports
+    % of this module and for the *implementation* imports of
+    % its ancestors.  This is because if this module is defined
+    % in the implementation section of its parent, then the
+    % interface of this module may depend on things
+    % imported only by its parent's implementation.
+    %
+    % If this module was actually defined in the interface
+    % section of one of its ancestors, then it should only
+    % depend on the interface imports of that ancestor,
+    % so the dependencies added here are in fact more
+    % conservative than they need to be in that case.
+    % However, that should not be a major problem.
+    %
+    ModuleName = ModuleImports ^ module_name,
+    ParentDeps = ModuleImports ^ parent_deps,
+    svrelation__add_element(ModuleName, IntModuleKey, !IntRel),
+    add_int_deps(IntModuleKey, ModuleImports, !IntRel),
+    add_parent_impl_deps_list(LookupModuleImports, IntModuleKey, ParentDeps,
+        !IntRel),
+
+    %
+    % Add implementation dependencies to the impl. deps relation.
+    % (The implementation dependencies are a superset of the
+    % interface dependencies.)
+    %
+    % Note that we need to do this both for the imports
+    % of this module and for the imports of its parents,
+    % because this module may depend on things imported
+    % only by its parents.
+    %
+    svrelation__add_element(ModuleName, ImplModuleKey, !ImplRel),
+    add_impl_deps(ImplModuleKey, ModuleImports, !ImplRel),
+    add_parent_impl_deps_list(LookupModuleImports, ImplModuleKey, ParentDeps,
+        !ImplRel).
+
     % Add interface dependencies to the interface deps relation.
     %
 :- pred add_int_deps(relation_key::in, module_imports::in,
@@ -4389,18 +4429,20 @@
     % Add parent implementation dependencies for the given Parent module
     % to the impl. deps relation values for the given ModuleKey.
     %
-:- pred add_parent_impl_deps(deps_map::in, relation_key::in, module_name::in,
-    deps_rel::in, deps_rel::out) is det.
+:- pred add_parent_impl_deps(lookup_module_imports::lookup_module_imports,
+    relation_key::in, module_name::in, deps_rel::in, deps_rel::out) is det.
 
-add_parent_impl_deps(DepsMap, ModuleKey, Parent, !Rel) :-
-    map__lookup(DepsMap, Parent, deps(_, ParentModuleImports)),
+add_parent_impl_deps(LookupModuleImports, ModuleKey, Parent, !Rel) :-
+    ParentModuleImports = LookupModuleImports(Parent),
     add_impl_deps(ModuleKey, ParentModuleImports, !Rel).
 
-:- pred add_parent_impl_deps_list(deps_map::in, relation_key::in,
-    list(module_name)::in, deps_rel::in, deps_rel::out) is det.
+:- pred add_parent_impl_deps_list(lookup_module_imports::lookup_module_imports,
+    relation_key::in, list(module_name)::in, deps_rel::in, deps_rel::out)
+    is det.
 
-add_parent_impl_deps_list(DepsMap, ModuleKey, Parents, !Rel) :-
-    list__foldl(add_parent_impl_deps(DepsMap, ModuleKey), Parents, !Rel).
+add_parent_impl_deps_list(LookupModuleImports, ModuleKey, Parents, !Rel) :-
+    list__foldl(add_parent_impl_deps(LookupModuleImports, ModuleKey), Parents,
+        !Rel).
 
     % Add a single dependency to a relation.
     %
Index: compiler/options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/options.m,v
retrieving revision 1.494
diff -u -r1.494 options.m
--- compiler/options.m	6 Feb 2006 05:39:43 -0000	1.494
+++ compiler/options.m	8 Feb 2006 06:28:32 -0000
@@ -758,6 +758,7 @@
     ;       help
     ;       version
     ;       fullarch
+    ;       local_module_id
     ;       compiler_sufficiently_recent
             % This option is used to test that the compiler is sufficiently
             % recent when no other test can easily be constructed in
@@ -1491,6 +1492,7 @@
     help                                -   bool(no),
     version                             -   bool(no),
     fullarch                            -   string(""),
+    local_module_id                     -   accumulating([]),
     compiler_sufficiently_recent        -   bool(no),
     experiment                          -   string("")
 ]).
@@ -2238,6 +2240,7 @@
 long_option("filenames-from-stdin", filenames_from_stdin).
 long_option("aditi-user",           aditi_user).
 long_option("fullarch",             fullarch).
+long_option("local-module-id",      local_module_id).
 long_option("bug-intermod-2002-06-13",  compiler_sufficiently_recent).
 long_option("bug-foreign_import-2002-08-06", compiler_sufficiently_recent).
 long_option("install-opt-files-2002-08-30", compiler_sufficiently_recent).
@@ -4591,6 +4594,8 @@
 
         % The `--fullarch' option is reserved for
         % use by the `Mercury.config' file.
+
+        % The `--local-module-id' option is used by `mmc --make'.
     ]).
 
 :- pred write_tabbed_lines(list(string)::in, io::di, io::uo) is det.
--------------------------------------------------------------------------
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