[m-rev.] for review: more analysis framework fixes/changes

Peter Wang novalazy at gmail.com
Tue Jun 3 17:35:21 AEST 2008


Branches: main

More changes to the intermodule analysis framework.  This patch mainly deals
with incorrect treatment of :- external procedures, opt_imported procedures,
and forcing the correct reanalyses when answers change or requests are
satisfied.

- Previously, the way to ensure that a module M is reanalysed if a request in
  module N is satisfied was, while analysing M: assume an answer for the
  procedure in N; record that as a result in N; and record that M has a
  dependency on that answer.  When N is analysed, if the real answer is
  better than the assumed answer, M would be marked `suboptimal' and later
  reanalysed.

  That's complicated and wasn't always done correctly.  Now we remember the
  module which makes a request.  When the request is satisfied, we mark the
  requesting module as `suboptimal'.  This also means the `.analysis' file of
  a module will only be modified when analysing that module and no others,
  which should be useful for parallel builds.

- In most analyses we weren't recording results for exported `:- external'
  procedures as we don't have their clauses and don't analyse them.  Other
  modules would happily make requests for `:- external' procedures, which
  would never be satisfied.

- We shouldn't make intermodule requests for `opt_imported' procedures as we
  actually have their clauses.  Even if the request is satisfied, we'd
  probably not look them up since we do have their clauses.

- If a module M opt_imports a procedure P from module N (its clauses are
  available while analysing M) then M also needs to depend on any answers
  required by P.  Otherwise a change to an answer required by P won't cause M
  to be reanalysed.

- There doesn't seem to be any reason to keep track of the analysis status of
  individual results.  If an answer changes requiring another module to be
  reanalysed, the *whole module* will be marked suboptimal or invalid.  And
  if that results in changed answers, its dependant modules will be marked.
  This patch doesn't remove the status of individual results but makes them
  always `optimal'.


compiler/analysis.m:
	Remember the name of the module being analysed in the analysis_info.
	Simplify some predicate interfaces with this information.

	Remember whether we're currently making an analysis file or just
	reading from them.  Make the record_* predicates do nothing in the
	latter case, so the caller doesn't need to check.  Also make the
	record predicates do the right thing if the callee module is
	non-local, e.g.  don't make requests to non-local modules.

	Automatically add a request if depending on a result that doesn't
	exist.

	Add a procedure to return the existing call patterns for a procedure,
	regardless of whether the module has been marked `invalid'.

	Add some assertions to check the analysis framework is being used as
	intended.

	Minor cleanups.

compiler/analysis.file.m:
	Record the module that made the request in `.request' files.

	Bump the analysis file version number.

compiler/hlds_module.m:
	Pass extra arguments to `init_analysis_info'.

compiler/hlds_pred.m:
	Add `pred_info_is_imported_not_external' which doesn't succeed on
	`:- external' procedures (defined in the current module), unlike
	`pred_info_is_imported'.

compiler/exception_analysis.m:
compiler/tabling_analysis.m:
compiler/trailing_analysis.m:
compiler/unused_args.m:
	Record results for `:- external' procedures.

	Don't look up results for our own `:- external' procedures from the
	analysis registry.  In general, fix many spots where external procs
	would be treated as imported.

	Write out results for procedures which are exported to submodules.

	Conform to analysis framework changes.  Remove some redundant checks
	which have been moved into the framework.

compiler/mercury_compile.m:
	Conform to analysis framework changes.

compiler/structure_reuse.analysis.m:
	Be careful not to read in requests and call patterns for
	`opt_imported' procedures as if they were defined in the current
	module.

	If depending on an answer that doesn't exist, also make a request for
	that answer.

	Conform to analysis framework changes.

	Write out messages when removing useless reuse version procedures.

compiler/structure_reuse.indirect.m:
	Use `pred_info_is_imported_not_external' so as not to look up results
	for our own `:- external' procedures from the analysis registry.

	Treat `opt_imported' procedures as intra-module as far as requests
	are concerned.  We need to satisfy requests for them in the current
	compiler invocation rather than when analysing imported modules.

compiler/structure_sharing.analysis.m:
	Fix treatment of `:- external' procedures.

	Conform to analysis framework changes.

compiler/structure_sharing.domain.m:
	Don't return suboptimal when unable to look up a result.

compiler/mmc_analysis.m:
	Replace pred_or_func_name_arity_to_func_id by a higher-level
	predicate.

tests/Mmakefile:
tests/analysis/Mmakefile:
tests/analysis/common.sh:
tests/analysis/excp/Mercury.options:
tests/analysis/excp/Mmakefile:
tests/analysis/excp/excp_m1.m.exception:
tests/analysis/excp/excp_m1.m.no_exception:
tests/analysis/excp/excp_m2.m:
tests/analysis/excp/excp_m3.m:
tests/analysis/excp/excp_runtest.sh:
tests/analysis/ext/Mercury.options:
tests/analysis/ext/Mmakefile:
tests/analysis/ext/ext.m:
tests/analysis/ext/ext2.m:
tests/analysis/ext/ext2_runtest.sh:
tests/analysis/ext/ext_runtest.sh:
tests/analysis/sharing/Mercury.options:
tests/analysis/sharing/Mmakefile:
tests/analysis/sharing/sharing_m1.m.no_share:
tests/analysis/sharing/sharing_m1.m.share:
tests/analysis/sharing/sharing_m2.m:
tests/analysis/sharing/sharing_m3.m:
tests/analysis/sharing/sharing_runtest.sh:
tests/analysis/table/Mercury.options:
tests/analysis/table/Mmakefile:
tests/analysis/table/table_m1.m.no_tabling:
tests/analysis/table/table_m1.m.tabling:
tests/analysis/table/table_m2.m:
tests/analysis/table/table_m3.m:
tests/analysis/table/table_runtest.sh:
tests/analysis/trail/Mercury.options:
tests/analysis/trail/Mmakefile:
tests/analysis/trail/trail_m1.m.no_trail:
tests/analysis/trail/trail_m1.m.trail:
tests/analysis/trail/trail_m2.m:
tests/analysis/trail/trail_m3.m:
tests/analysis/trail/trail_runtest.sh:
tests/analysis/unused_args/Mercury.options:
tests/analysis/unused_args/Mmakefile:
tests/analysis/unused_args/ua_m1.m.no_unused_args:
tests/analysis/unused_args/ua_m1.m.unused_args:
tests/analysis/unused_args/ua_m2.m:
tests/analysis/unused_args/ua_m3.m:
tests/analysis/unused_args/unused_args_runtest.sh:
	Add test cases.


Index: compiler/analysis.file.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/analysis.file.m,v
retrieving revision 1.4
diff -u -p -r1.4 analysis.file.m
--- compiler/analysis.file.m	29 May 2008 04:41:54 -0000	1.4
+++ compiler/analysis.file.m	3 Jun 2008 07:32:23 -0000
@@ -132,14 +132,14 @@
 % The format of an analysis request file is:
 %
 % version_number.
-% analysis_name(analysis_version, func_id, call_pattern).
+% calling_module -> analysis_name(analysis_version, func_id, call_pattern).
 
 :- type invalid_analysis_file
     --->    invalid_analysis_file(string).
 
 :- func version_number = int.
 
-version_number = 4.
+version_number = 5.
 
 :- func analysis_registry_suffix = string.
 
@@ -385,8 +385,10 @@ read_module_analysis_requests(Info, Modu
 
 parse_request_entry(Compiler, Term, Requests0, Requests) :-
     (
-        Term = term.functor(term.atom(AnalysisName),
+        Term = term.functor(atom("->"), [CallerModuleTerm, RHS], _),
+        RHS = term.functor(atom(AnalysisName),
             [VersionNumberTerm, FuncIdTerm, CallPatternTerm], _),
+        term_to_type(CallerModuleTerm, CallerModule),
         term_to_type(FuncIdTerm, FuncId),
         CallPatternTerm = term.functor(
             term.string(CallPatternString), [], _),
@@ -399,7 +401,7 @@ parse_request_entry(Compiler, Term, Requ
             VersionNumberTerm = term.functor(
                 term.integer(VersionNumber), [], _)
         ->
-            Result = 'new analysis_request'(CallPattern),
+            Result = 'new analysis_request'(CallPattern, CallerModule),
             ( AnalysisRequests0 = map.search(Requests0, AnalysisName) ->
                 AnalysisRequests1 = AnalysisRequests0
             ;
@@ -666,8 +668,8 @@ write_module_analysis_requests(Info, Mod
     `with_type` write_entry(analysis_request)
     `with_inst` write_entry <= compiler(Compiler).
 
-write_request_entry(Compiler, AnalysisName, FuncId, analysis_request(Call),
-        !IO) :-
+write_request_entry(Compiler, AnalysisName, FuncId, Request, !IO) :-
+    Request = analysis_request(Call, CallerModule),
     (
         analysis_type(_ : unit(Call), _ : unit(Answer)) =
             analyses(Compiler, AnalysisName)
@@ -678,11 +680,16 @@ write_request_entry(Compiler, AnalysisNa
             "write_request_entry: unknown analysis type")
     ),
     term_io.write_term_nl(varset.init : varset,
+        functor(atom("->"), [
+            type_to_term(CallerModule),
+            CallTerm
+        ], context_init), !IO),
+    CallTerm =
         functor(atom(AnalysisName), [
             functor(integer(VersionNumber), [], context_init),
             type_to_term(FuncId),
             functor(string(to_string(Call)), [], context_init)
-        ], context_init), !IO).
+        ], context_init).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/analysis.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/analysis.m,v
retrieving revision 1.5
diff -u -p -r1.5 analysis.m
--- compiler/analysis.m	29 May 2008 04:41:54 -0000	1.5
+++ compiler/analysis.m	3 Jun 2008 07:32:23 -0000
@@ -169,14 +169,26 @@
                 fid_mode    :: proc_id
             ).
 
-    % Holds information used while analysing a module.
 :- type analysis_info.
 
-:- func init_analysis_info(Compiler) = analysis_info <= compiler(Compiler).
+:- func init_analysis_info(Compiler, module_name, bool) = analysis_info
+    <= compiler(Compiler).
 
 %-----------------------------------------------------------------------------%
 
+    % Look up call patterns for all results for a given function.
+    % Even if the module is `invalid' the call patterns will be returned.
+    %
+    % You should use this when you want to know which call patterns were
+    % produced for a procedure defined in the current module in previous
+    % passes.
+    %
+:- pred lookup_existing_call_patterns(analysis_info::in, analysis_name::in,
+    module_name::in, func_id::in, list(Call)::out) is det
+    <= call_pattern(FuncInfo, Call).
+
     % Look up all results for a given function.
+    % If the module is `invalid' then the result list will be empty.
     %
     % N.B. Newly recorded results will NOT be found. This is intended
     % for looking up results from _other_ modules.
@@ -211,46 +223,54 @@
     FuncInfo::in, Call::in, maybe(analysis_result(Call, Answer))::out) is det
     <= analysis(FuncInfo, Call, Answer).
 
-    % Record an analysis result for a (usually local) function.
-    %
-    % XXX At the moment the result is assumed to be for a function local to
-    % the currently-compiled module and things will probably break if it isn't.
+    % Record an analysis result for a function.
+    % Abort if the function is not from the module being analysed.
+    % Does nothing if not making the analysis registry.
     %
 :- pred record_result(module_name::in, func_id::in, Call::in, Answer::in,
     analysis_status::in, analysis_info::in, analysis_info::out) is det
     <= analysis(FuncInfo, Call, Answer).
 
-    % Record the dependency of a module on the analysis result of another
-    % module.
+    % Record the dependency of the module being analysed on the analysis
+    % result of another module.
+    % Does nothing if not making the analysis registry or if the result
+    % that is depended upon comes from a non-local module.
+    % Automatically makes a request if the call pattern hasn't been seen
+    % before for that function.
     %
-:- pred record_dependency(module_name::in, analysis_name::in, module_name::in,
-    func_id::in, Call::in, analysis_info::in, analysis_info::out) is det
-    <= call_pattern(FuncInfo, Call).
+:- pred record_dependency(module_name::in, func_id::in, FuncInfo::in,
+    Call::in, Answer::unused, analysis_info::in, analysis_info::out) is det
+    <= analysis(FuncInfo, Call, Answer).
 
-    % Lookup all the requests for a given (usually local) function.
+    % Lookup all the requests for a given function.
+    % Abort if the function is not from the module being analysed.
     %
 :- pred lookup_requests(analysis_info::in, analysis_name::in, module_name::in,
     func_id::in, list(Call)::out) is det
     <= call_pattern(FuncInfo, Call).
 
-    % Record a request for a function in an imported module.
+    % Record a request from the module being analysed on a function defined
+    % in an imported module.
+    % Does nothing if not making the analysis registry or if the function is
+    % defined in a non-local module.
     %
-:- pred record_request(analysis_name::in, module_name::in, func_id::in,
-    Call::in, analysis_info::in, analysis_info::out) is det
+:- pred record_request(analysis_name::in, module_name::in,
+    func_id::in, Call::in, analysis_info::in, analysis_info::out) is det
     <= call_pattern(FuncInfo, Call).
 
 %-----------------------------------------------------------------------------%
 
-    % prepare_intermodule_analysis(ThisModuleName, ModuleNames,
-    %   LocalModuleNames, !Info, !IO)
+    % prepare_intermodule_analysis(ImportedModuleNames, LocalModuleNames,
+    %   !Info, !IO)
     %
     % This predicate should be called before any pass begins to use the
     % analysis framework.  It ensures that all the analysis files 
-    % are loaded so that lookups can be satisfied.  ModuleNames is the set of
-    % all modules that are directly or indirectly imported by the module being
-    % analysed.  LocalModuleNames is the set of non-"library" modules.
+    % are loaded so that lookups can be satisfied.  ImportedModuleNames is the
+    % set of all modules that are directly or indirectly imported by the
+    % module being analysed.  LocalModuleNames is the set of non-"library"
+    % modules.
     %
-:- pred prepare_intermodule_analysis(module_name::in, set(module_name)::in,
+:- pred prepare_intermodule_analysis(set(module_name)::in,
     set(module_name)::in, analysis_info::in, analysis_info::out,
     io::di, io::uo) is det.
 
@@ -267,7 +287,7 @@
     % requests and results for the current compilation to the
     % analysis files.
     %
-:- pred write_analysis_files(Compiler::in, module_info::in, module_name::in,
+:- pred write_analysis_files(Compiler::in, module_info::in,
     set(module_name)::in, analysis_info::in, analysis_info::out,
     io::di, io::uo) is det
     <= compiler(Compiler).
@@ -299,6 +319,7 @@
 
 :- import_module map.
 :- import_module string.
+:- import_module type_desc.
 :- import_module univ.
 
 %-----------------------------------------------------------------------------%
@@ -308,6 +329,15 @@
             analysis_info(
                 compiler :: Compiler,
 
+                % The module being analysed.
+                %
+                this_module :: module_name,
+
+                % Whether we are making the analysis registry or just using
+                % results for .analysis files.
+                %
+                make_analysis_registry :: make_analysis_registry,
+
                 % The set of local modules, i.e. for which we can issue
                 % requests.
                 %
@@ -333,7 +363,8 @@
                 % into the "old" map, from where they can be written to disk.
                 %
                 old_analysis_results :: analysis_map(some_analysis_result),
-                new_analysis_results :: analysis_map(some_analysis_result),
+                new_analysis_results :: module_analysis_map(
+                                            some_analysis_result),
 
                 % The Inter-module Dependency Graph records dependencies
                 % of an entire module's analysis results on another module's
@@ -357,6 +388,10 @@
             )
             => compiler(Compiler).
 
+:- type make_analysis_registry
+    --->    make_analysis_registry
+    ;       use_analysis_registry_only.
+
     % An analysis result is a call pattern paired with an answer.
     % The result has a status associated with it.
     %
@@ -372,17 +407,20 @@
 :- type analysis_request
     --->    some [FuncInfo, Call]
             analysis_request(
-                Call
+                req_call        :: Call,
+                req_caller      :: module_name
             )
             => call_pattern(FuncInfo, Call).
 
 :- type imdg_arc
     --->    some [FuncInfo, Call]
             imdg_arc(
-                Call,       % Call pattern of the analysis result
-                            % being depended on.
-                module_name   % The module that _depends on_ this function's
-                            % result.
+                imdg_call       :: Call,
+                                % Call pattern of the analysis result
+                                % being depended on.
+                imdg_caller     :: module_name
+                                % The module that _depends on_ this
+                                % function's result.
             )
             => call_pattern(FuncInfo, Call).
 
@@ -411,20 +449,48 @@
 
 %-----------------------------------------------------------------------------%
 
-init_analysis_info(Compiler) =
-    'new analysis_info'(Compiler, set.init, map.init, map.init, map.init,
-        map.init, map.init, map.init).
+init_analysis_info(Compiler, ThisModuleName, MakeAnalysisRegBool) = Info :-
+    (
+        MakeAnalysisRegBool = yes,
+        MakeAnalysisReg = make_analysis_registry
+    ;
+        MakeAnalysisRegBool = no,
+        MakeAnalysisReg = use_analysis_registry_only
+    ),
+    Info = 'new analysis_info'(Compiler, ThisModuleName, MakeAnalysisReg,
+        set.init, map.init, map.init, map.init, map.init, map.init, map.init).
 
 %-----------------------------------------------------------------------------%
 
+lookup_existing_call_patterns(Info, AnalysisName, ModuleName, FuncId, Calls) :-
+    ( ModuleName = Info ^ this_module ->
+        true
+    ;
+        unexpected(this_file, "lookup_existing_call_patterns: not this_module")
+    ),
+    Map = Info ^ old_analysis_results,
+    (
+        ModuleResults = Map ^ elem(ModuleName),
+        Results = ModuleResults ^ elem(AnalysisName) ^ elem(FuncId)
+    ->
+        Calls = list.map(
+            (func(Result) = Call :-
+                Result = some_analysis_result(Call0, _Answer, _Status),
+                det_univ_to_type(univ(Call0), Call)
+            ), Results)
+    ;
+        Calls = []
+    ).
+
 lookup_results(Info, ModuleName, FuncId, ResultList) :-
-    lookup_results(Info, ModuleName, FuncId, no, ResultList).
+    AllowInvalidModules = no,
+    lookup_results_1(Info, ModuleName, FuncId, AllowInvalidModules, ResultList).
 
-:- pred lookup_results(analysis_info::in, module_name::in, func_id::in,
+:- pred lookup_results_1(analysis_info::in, module_name::in, func_id::in,
     bool::in, list(analysis_result(Call, Answer))::out) is det
     <= analysis(FuncInfo, Call, Answer).
 
-lookup_results(Info, ModuleName, FuncId, AllowInvalidModules, ResultList) :-
+lookup_results_1(Info, ModuleName, FuncId, AllowInvalidModules, ResultList) :-
     trace [io(!IO)] (
         debug_msg((pred(!.IO::di, !:IO::uo) is det :-
             io.write_string("% Looking up analysis results for ", !IO),
@@ -451,9 +517,9 @@ lookup_results(Info, ModuleName, FuncId,
         )
     ).
 
-:- pred lookup_results_2(analysis_map(some_analysis_result)::in, module_name::in,
-    func_id::in, list(analysis_result(Call, Answer))::out) is det
-    <= analysis(FuncInfo, Call, Answer).
+:- pred lookup_results_2(analysis_map(some_analysis_result)::in,
+    module_name::in, func_id::in, list(analysis_result(Call, Answer))::out)
+    is det <= analysis(FuncInfo, Call, Answer).
 
 lookup_results_2(Map, ModuleName, FuncId, ResultList) :-
     AnalysisName = analysis_name(_ : Call, _ : Answer),
@@ -525,7 +591,9 @@ more_precise_answer(FuncInfo, Result, Be
 
 lookup_exactly_matching_result_even_from_invalid_modules(Info, ModuleName,
         FuncId, FuncInfo, Call, MaybeResult) :-
-    lookup_results(Info, ModuleName, FuncId, yes, AllResultsList),
+    AllowInvalidModules = yes,
+    lookup_results_1(Info, ModuleName, FuncId, AllowInvalidModules,
+        AllResultsList),
     ResultList = list.filter(
         (pred(R::in) is semidet :-
             equivalent(FuncInfo, Call, R ^ ar_call)
@@ -546,50 +614,64 @@ lookup_exactly_matching_result_even_from
 %-----------------------------------------------------------------------------%
 
 record_result(ModuleName, FuncId, CallPattern, AnswerPattern, Status, !Info) :-
-    Map0 = !.Info ^ new_analysis_results,
-    record_result_in_analysis_map(ModuleName, FuncId,
-    CallPattern, AnswerPattern, Status, Map0, Map),
-    !Info ^ new_analysis_results := Map.
+    ( ModuleName = !.Info ^ this_module ->
+        true
+    ;
+        unexpected(this_file,
+            "record_result: recording result for procedure " ++
+            "defined in another module")
+    ),
+
+    MakeAnalysisReg = !.Info ^ make_analysis_registry,
+    (
+        MakeAnalysisReg = make_analysis_registry,
+        Map0 = !.Info ^ new_analysis_results,
+        record_result_in_analysis_map(FuncId, CallPattern, AnswerPattern,
+            Status, Map0, Map),
+        !Info ^ new_analysis_results := Map
+    ;
+        MakeAnalysisReg = use_analysis_registry_only
+    ).
 
-:- pred record_result_in_analysis_map(module_name::in, func_id::in,
+:- pred record_result_in_analysis_map(func_id::in,
     Call::in, Answer::in, analysis_status::in,
-    analysis_map(some_analysis_result)::in,
-    analysis_map(some_analysis_result)::out) is det
+    module_analysis_map(some_analysis_result)::in,
+    module_analysis_map(some_analysis_result)::out) is det
     <= analysis(FuncInfo, Call, Answer).
 
-record_result_in_analysis_map(ModuleName, FuncId,
-        CallPattern, AnswerPattern, Status, !Map) :-
-    ( ModuleResults0 = map.search(!.Map, ModuleName) ->
-        ModuleResults1 = ModuleResults0
-    ;
-        ModuleResults1 = map.init
-    ),
+record_result_in_analysis_map(FuncId, CallPattern, AnswerPattern, Status,
+        ModuleResults0, ModuleResults) :-
     AnalysisName = analysis_name(CallPattern, AnswerPattern),
-    ( AnalysisResults0 = map.search(ModuleResults1, AnalysisName) ->
+    ( map.search(ModuleResults0, AnalysisName, AnalysisResults0) ->
         AnalysisResults1 = AnalysisResults0
     ;
         AnalysisResults1 = map.init
     ),
-    ( FuncResults0 = map.search(AnalysisResults1, FuncId) ->
+    ( map.search(AnalysisResults1, FuncId, FuncResults0) ->
         FuncResults1 = FuncResults0
     ;
         FuncResults1 = []
     ),
-    !:Map = map.set(!.Map, ModuleName,
-        map.set(ModuleResults1, AnalysisName,
-            map.set(AnalysisResults1, FuncId, FuncResults))),
+    Result = 'new some_analysis_result'(CallPattern, AnswerPattern, Status),
     FuncResults = [Result | FuncResults1],
-    Result = 'new some_analysis_result'(CallPattern, AnswerPattern, Status).
+    ModuleResults =
+        map.set(ModuleResults0, AnalysisName,
+            map.set(AnalysisResults1, FuncId, FuncResults)).
 
 %-----------------------------------------------------------------------------%
 
 lookup_requests(Info, AnalysisName, ModuleName, FuncId, CallPatterns) :-
+    ( ModuleName = Info ^ this_module ->
+        true
+    ;
+        unexpected(this_file, "lookup_requests: not this_module")
+    ),
     (
         map.search(Info ^ analysis_requests, ModuleName, ModuleRequests),
         CallPatterns0 = ModuleRequests ^ elem(AnalysisName) ^ elem(FuncId)
     ->
         CallPatterns1 = list.filter_map(
-            (func(analysis_request(Call0)) = Call is semidet :-
+            (func(analysis_request(Call0, _)) = Call is semidet :-
                 univ(Call) = univ(Call0)
             ), CallPatterns0),
         % Requests simply get appended to `.request' files so when we read them
@@ -600,6 +682,31 @@ lookup_requests(Info, AnalysisName, Modu
     ).
 
 record_request(AnalysisName, ModuleName, FuncId, CallPattern, !Info) :-
+    ThisModule = !.Info ^ this_module,
+    ( ThisModule = ModuleName ->
+        unexpected(this_file, "record_request: request on self")
+    ;
+        true
+    ),
+
+    MakeAnalysisReg = !.Info ^ make_analysis_registry,
+    module_is_local(!.Info, ModuleName, IsLocal),
+    (
+        MakeAnalysisReg = make_analysis_registry,
+        IsLocal = yes
+    ->
+        record_request_2(ThisModule, AnalysisName, ModuleName, FuncId,
+            CallPattern, !Info)
+    ;
+        true
+    ).
+
+:- pred record_request_2(module_name::in, analysis_name::in, module_name::in,
+    func_id::in, Call::in, analysis_info::in, analysis_info::out) is det
+    <= call_pattern(FuncInfo, Call).
+
+record_request_2(CallerModule, AnalysisName, ModuleName, FuncId, CallPattern,
+        !Info) :-
     ( ModuleResults0 = map.search(!.Info ^ analysis_requests, ModuleName) ->
         ModuleResults1 = ModuleResults0
     ;
@@ -615,50 +722,81 @@ record_request(AnalysisName, ModuleName,
     ;
         FuncResults1 = []
     ),
+    Request = 'new analysis_request'(CallPattern, CallerModule),
+    FuncResults = [Request | FuncResults1],
     !Info ^ analysis_requests :=
         map.set(!.Info ^ analysis_requests, ModuleName,
             map.set(ModuleResults1, AnalysisName,
-                map.set(AnalysisResults1, FuncId,
-                    ['new analysis_request'(CallPattern) | FuncResults1]))).
+                map.set(AnalysisResults1, FuncId, FuncResults))).
 
 %-----------------------------------------------------------------------------%
 
-record_dependency(CallerModuleName, AnalysisName, CalleeModuleName, FuncId, Call,
+record_dependency(CalleeModuleName, FuncId, FuncInfo, Call, DummyAnswer,
         !Info) :-
-    ( CallerModuleName = CalleeModuleName ->
-        % XXX this assertion breaks compiling the standard library with
-        % --analyse-trail-usage at the moment
-        %
-        % error("record_dependency: " ++ CalleeModuleName ++ " and " ++
-        %    CallerModuleName ++ " must be different")
-        true
+    ThisModule = !.Info ^ this_module,
+    ( ThisModule = CalleeModuleName ->
+        unexpected(this_file, "record_dependency: dependency on self")
     ;
-        ( Analyses0 = map.search(!.Info ^ new_imdg, CalleeModuleName) ->
-            Analyses1 = Analyses0
-        ;
-            Analyses1 = map.init
-        ),
-        ( Funcs0 = map.search(Analyses1, AnalysisName) ->
-            Funcs1 = Funcs0
-        ;
-            Funcs1 = map.init
-        ),
-        ( FuncArcs0 = map.search(Funcs1, FuncId) ->
-            FuncArcs1 = FuncArcs0
-        ;
-            FuncArcs1 = []
-        ),
-        Dep = 'new imdg_arc'(Call, CallerModuleName),
-        % XXX this should really be a set to begin with
-        ( list.member(Dep, FuncArcs1) ->
-            true
+        true
+    ),
+
+    MakeAnalysisReg = !.Info ^ make_analysis_registry,
+    module_is_local(!.Info, CalleeModuleName, IsLocal),
+    (
+        MakeAnalysisReg = make_analysis_registry,
+        IsLocal = yes
+    ->
+        AnalysisName = analysis_name(Call, DummyAnswer),
+        record_dependency_2(ThisModule, AnalysisName, CalleeModuleName, FuncId,
+            Call, !Info),
+
+        % If the call pattern that's being depended on hasn't been analysed
+        % before, make a request for it.
+        lookup_exactly_matching_result_even_from_invalid_modules(!.Info,
+            CalleeModuleName, FuncId, FuncInfo, Call, MaybeResult),
+        (
+            MaybeResult = no,
+            record_request(AnalysisName, CalleeModuleName, FuncId, Call, !Info)
         ;
-            !Info ^ new_imdg :=
-                map.set(!.Info ^ new_imdg, CalleeModuleName,
-                    map.set(Analyses1, AnalysisName,
-                        map.set(Funcs1, FuncId, FuncArcs))),
-                            FuncArcs = [Dep | FuncArcs1]
+            MaybeResult = yes(Result),
+            same_type(Result, analysis_result(Call, DummyAnswer, _))
         )
+    ;
+        true
+    ).
+
+:- pred record_dependency_2(module_name::in, analysis_name::in,
+    module_name::in, func_id::in, Call::in,
+    analysis_info::in, analysis_info::out) is det
+    <= call_pattern(FuncInfo, Call).
+
+record_dependency_2(CallerModuleName, AnalysisName, CalleeModuleName, FuncId,
+        Call, !Info) :-
+    ( Analyses0 = map.search(!.Info ^ new_imdg, CalleeModuleName) ->
+        Analyses1 = Analyses0
+    ;
+        Analyses1 = map.init
+    ),
+    ( Funcs0 = map.search(Analyses1, AnalysisName) ->
+        Funcs1 = Funcs0
+    ;
+        Funcs1 = map.init
+    ),
+    ( FuncArcs0 = map.search(Funcs1, FuncId) ->
+        FuncArcs1 = FuncArcs0
+    ;
+        FuncArcs1 = []
+    ),
+    Dep = 'new imdg_arc'(Call, CallerModuleName),
+    % XXX this should really be a set to begin with
+    ( list.member(Dep, FuncArcs1) ->
+        true
+    ;
+        FuncArcs = [Dep | FuncArcs1],
+        !Info ^ new_imdg :=
+            map.set(!.Info ^ new_imdg, CalleeModuleName,
+                map.set(Analyses1, AnalysisName,
+                    map.set(Funcs1, FuncId, FuncArcs)))
     ).
 
 %-----------------------------------------------------------------------------%
@@ -688,13 +826,17 @@ record_dependency(CallerModuleName, Anal
     % Finally, clear out the "new" analysis results map.  When we write
     % out the analysis files we will do it from the "old" results map.
     %
+    % In a similar way, any new results which satisfy a request cause the
+    % module that made the request to be marked suboptimal. 
+    %
 :- pred update_analysis_registry(module_info::in,
     analysis_info::in, analysis_info::out, io::di, io::uo) is det.
 
 update_analysis_registry(ModuleInfo, !Info, !IO) :-
     debug_msg(io.write_string("% Updating analysis registry.\n"), !IO),
     NewResults = !.Info ^ new_analysis_results,
-    map.foldl2(update_analysis_registry_2(ModuleInfo), NewResults, !Info, !IO),
+    update_analysis_registry_2(ModuleInfo, !.Info ^ this_module, NewResults,
+        !Info, !IO),
     !Info ^ new_analysis_results := map.init.
 
 :- pred update_analysis_registry_2(module_info::in, module_name::in,
@@ -741,18 +883,8 @@ update_analysis_registry_5(ModuleInfo, M
         MaybeResult = yes(OldResult),
         OldResult = analysis_result(_OldCall, OldAnswer, OldStatus),
         ( equivalent(FuncInfo, NewAnswer, OldAnswer) ->
-            debug_msg((pred(!.IO::di, !:IO::uo) is det :-
-                io.write_string("% No change in the result ", !IO),
-                io.write(ModuleName, !IO),
-                io.write_string(".", !IO),
-                io.write(FuncId, !IO),
-                io.write_string(":", !IO),
-                io.write(Call, !IO),
-                io.write_string(" --> ", !IO),
-                io.write(NewAnswer, !IO),
-                io.nl(!IO)
-            ), !IO),
-
+            debug_msg(write_no_change_in_result(ModuleName, FuncId, Call,
+                NewAnswer), !IO),
             ( NewStatus \= OldStatus ->
                 OldMap0 = !.Info ^ old_analysis_results,
                 replace_result_in_analysis_map(ModuleName, FuncId, FuncInfo,
@@ -777,22 +909,11 @@ update_analysis_registry_5(ModuleInfo, M
             ;
                 Status = invalid
             ),
-            debug_msg((pred(!.IO::di, !:IO::uo) is det :-
-                io.write_string("% ", !IO),
-                io.write(OldAnswer, !IO),
-                io.write_string(" changed to ", !IO),
-                io.write(NewAnswer, !IO),
-                io.nl(!IO),
-                io.write_string("Mark dependent modules as ", !IO),
-                io.write(Status, !IO),
-                io.nl(!IO),
-                io.write_string("The modules to mark are: ", !IO),
-                io.write(DepModules, !IO),
-                io.nl(!IO)
-            ), !IO),
             OldArcs = !.Info ^ old_imdg ^ det_elem(ModuleName),
             DepModules = imdg_dependent_modules(OldArcs, AnalysisName,
                 FuncId, FuncInfo, Call),
+            debug_msg(write_changed_answer(OldAnswer, NewAnswer, Status,
+                DepModules), !IO),
             set.fold2(taint_module_overall_status(Status), DepModules,
                 !Info, !IO)
         )
@@ -800,10 +921,35 @@ update_analysis_registry_5(ModuleInfo, M
         % There was no previous answer for this call pattern.
         % Just add this result to the registry.
         MaybeResult = no,
-        OldMap0 = !.Info ^ old_analysis_results,
-        record_result_in_analysis_map(ModuleName, FuncId,
-            Call, NewAnswer, NewStatus, OldMap0, OldMap),
-        !Info ^ old_analysis_results := OldMap
+        OldMap0 = !.Info ^ old_analysis_results ^ det_elem(ModuleName),
+        record_result_in_analysis_map(FuncId, Call, NewAnswer, NewStatus,
+            OldMap0, OldMap),
+        !Info ^ old_analysis_results ^ elem(ModuleName) := OldMap
+    ),
+
+    % If this new result satisfies a request then mark the requesting modules
+    % as suboptimal so they can be reanalysed.
+    %
+    % Ideally we could compare the new answer with either a default answer that
+    % the calling module probably used, or each request could optionally record
+    % what answer the caller assumed.  Then we could avoid reanalysing the
+    % calling module unnecessarily.  (This only reason we don't implement
+    % the former is that the structure reuse analysis doesn't implement
+    % the `top' typeclass method.)
+    (
+        map.search(!.Info ^ analysis_requests, ModuleName, ModuleRequests),
+        Requests = ModuleRequests ^ elem(AnalysisName) ^ elem(FuncId),
+        Requests = [_ | _]
+    ->
+        Callers0 = list.filter_map(
+            (func(analysis_request(Call0, Caller)) = Caller is semidet :-
+                univ(Call0) = univ(Call0)
+            ), Requests),
+        list.sort_and_remove_dups(Callers0, Callers),
+        list.foldl2(taint_module_overall_status(suboptimal), Callers,
+            !Info, !IO)
+    ;
+        true
     ).
 
     % Replace an analysis result for the given function/call pattern with a
@@ -886,24 +1032,70 @@ taint_module_overall_status(Status, Modu
         ; Status = invalid
         ),
 
-        % We may not have loaded the analysis results for this module yet.
+        % We may not have read the overall status for this module yet.
         % Even though we loaded all the analysis files of modules reachable
         % from the initial module beforehand, a _caller_ of the initial module
         % may not be part of that set.
-        ensure_old_module_analysis_results_loaded(ModuleName, !Info, !IO),
+        ensure_module_status_loaded(ModuleName, !Info, !IO),
 
         ModuleStatus0 = !.Info ^ module_statuses ^ det_elem(ModuleName),
         ModuleStatus = lub(ModuleStatus0, Status),
-        debug_msg((pred(!.IO::di, !:IO::uo) is det :-
-            io.print("% Tainting the overall module status of ", !IO),
-            io.print(ModuleName, !IO),
-            io.print(" with ", !IO),
-            io.print(ModuleStatus, !IO),
-            io.nl(!IO)
-        ), !IO),
+        debug_msg(write_tainting_module(ModuleName, ModuleStatus), !IO),
         !Info ^ module_statuses ^ elem(ModuleName) := ModuleStatus
     ).
 
+:- pred ensure_module_status_loaded(module_name::in,
+    analysis_info::in, analysis_info::out, io::di, io::uo) is det.
+
+ensure_module_status_loaded(ModuleName, !Info, !IO) :-
+    ( map.contains(!.Info ^ module_statuses, ModuleName) ->
+        true
+    ;
+        analysis.read_module_overall_status(!.Info ^ compiler, ModuleName,
+            ModuleStatus, !IO),
+        !Info ^ module_statuses ^ elem(ModuleName) := ModuleStatus
+    ).
+
+:- pred write_no_change_in_result(module_name::in, func_id::in, Call::in,
+    Answer::in, io::di, io::uo) is det.
+
+write_no_change_in_result(ModuleName, FuncId, Call, NewAnswer, !IO) :-
+    io.write_string("% No change in the result ", !IO),
+    io.write(ModuleName, !IO),
+    io.write_string(".", !IO),
+    io.write(FuncId, !IO),
+    io.write_string(":", !IO),
+    io.write(Call, !IO),
+    io.write_string(" --> ", !IO),
+    io.write(NewAnswer, !IO),
+    io.nl(!IO).
+
+:- pred write_changed_answer(Answer::in, Answer::in, analysis_status::in,
+    set(module_name)::in, io::di, io::uo) is det.
+
+write_changed_answer(OldAnswer, NewAnswer, Status, DepModules, !IO) :-
+    io.write_string("% ", !IO),
+    io.write(OldAnswer, !IO),
+    io.write_string(" changed to ", !IO),
+    io.write(NewAnswer, !IO),
+    io.nl(!IO),
+    io.write_string("Mark dependent modules as ", !IO),
+    io.write(Status, !IO),
+    io.nl(!IO),
+    io.write_string("The modules to mark are: ", !IO),
+    io.write(DepModules, !IO),
+    io.nl(!IO).
+
+:- pred write_tainting_module(module_name::in, analysis_status::in,
+    io::di, io::uo) is det.
+
+write_tainting_module(ModuleName, ModuleStatus, !IO) :-
+    io.print("% Tainting the overall module status of ", !IO),
+    io.print(ModuleName, !IO),
+    io.print(" with ", !IO),
+    io.print(ModuleStatus, !IO),
+    io.nl(!IO).
+
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
@@ -915,24 +1107,19 @@ taint_module_overall_status(Status, Modu
 :- pred update_intermodule_dependencies(module_name::in, set(module_name)::in,
     analysis_info::in, analysis_info::out) is det.
 
-update_intermodule_dependencies(ModuleName, ImportedModules, !Info) :-
-    set.fold(update_intermodule_dependencies_2(ModuleName), ImportedModules,
-        !Info).
+update_intermodule_dependencies(ModuleName, LocalImportedModules, !Info) :-
+    set.fold(update_intermodule_dependencies_2(ModuleName),
+        LocalImportedModules, !Info).
 
 :- pred update_intermodule_dependencies_2(module_name::in, module_name::in,
     analysis_info::in, analysis_info::out) is det.
 
 update_intermodule_dependencies_2(ModuleName, ImportedModuleName, !Info) :-
+    map.lookup(!.Info ^ old_imdg, ImportedModuleName, IMDG0),
     trace [io(!IO)] (
-        debug_msg((pred(!.IO::di, !:IO::uo) is det :-
-            io.print("% Clearing entries involving ", !IO),
-            io.print(ModuleName, !IO),
-            io.print(" from ", !IO),
-            io.print(ImportedModuleName, !IO),
-            io.print("'s IMDG.\n", !IO)
-        ), !IO)
+        debug_msg(write_clearing_entries(ModuleName, ImportedModuleName),
+            !IO)
     ),
-    IMDG0 = !.Info ^ old_imdg ^ det_elem(ImportedModuleName),
     clear_imdg_entries_pointing_at(ModuleName, IMDG0, IMDG1),
 
     ( NewArcs = !.Info ^ new_imdg ^ elem(ImportedModuleName) ->
@@ -943,6 +1130,16 @@ update_intermodule_dependencies_2(Module
     !Info ^ old_imdg ^ elem(ImportedModuleName) := IMDG,
     !Info ^ new_imdg := map.delete(!.Info ^ new_imdg, ImportedModuleName).
 
+:- pred write_clearing_entries(module_name::in, module_name::in,
+    io::di, io::uo) is det.
+
+write_clearing_entries(ModuleName, ImportedModuleName, !IO) :-
+    io.write_string("% Clearing entries involving ", !IO),
+    io.write(ModuleName, !IO),
+    io.write_string(" from ", !IO),
+    io.write(ImportedModuleName, !IO),
+    io.write_string("'s IMDG.\n", !IO).
+
 :- pred clear_imdg_entries_pointing_at(module_name::in,
     module_analysis_map(imdg_arc)::in,
     module_analysis_map(imdg_arc)::out) is det.
@@ -962,7 +1159,7 @@ clear_imdg_entries_pointing_at_2(ModuleN
     list(imdg_arc)::in, list(imdg_arc)::out) is det.
 
 clear_imdg_entries_pointing_at_3(ModuleName, _, Arcs0, Arcs) :-
-    list.filter((pred(imdg_arc(_, ModId)::in) is semidet :- ModuleName \= ModId),
+    list.filter((pred(Arc::in) is semidet :- Arc ^ imdg_caller \= ModuleName),
         Arcs0, Arcs).
 
 :- pred combine_func_imdg(func_analysis_map(imdg_arc)::in,
@@ -978,31 +1175,31 @@ combine_imdg_lists(ArcsA, ArcsB, ArcsA +
 
 %-----------------------------------------------------------------------------%
 
-prepare_intermodule_analysis(ThisModuleName, ModuleNames, LocalModuleNames,
-        !Info, !IO) :-
-    set.fold2(ensure_analysis_files_loaded, ModuleNames, !Info, !IO),
-
-    % Read in requests for the module being analysed.
-    read_module_analysis_requests(!.Info, ThisModuleName, ThisModuleRequests,
-        !IO),
-    !Info ^ analysis_requests ^ elem(ThisModuleName) := ThisModuleRequests,
+prepare_intermodule_analysis(ImportedModuleNames0, LocalModuleNames, !Info,
+        !IO) :-
+    ThisModule = !.Info ^ this_module,
+    ImportedModuleNames = set.delete(ImportedModuleNames0, ThisModule),
 
-    !Info ^ local_module_names := LocalModuleNames.
+    !Info ^ local_module_names := LocalModuleNames,
 
-:- pred ensure_analysis_files_loaded(module_name::in,
-    analysis_info::in, analysis_info::out, io::di, io::uo) is det.
+    % Read in results for imported modules.
+    set.fold2(load_module_analysis_results, ImportedModuleNames, !Info, !IO),
 
-ensure_analysis_files_loaded(ModuleName, !Info, !IO) :-
-    ensure_old_module_analysis_results_loaded(ModuleName, !Info, !IO),
-    ensure_old_imdg_loaded(ModuleName, !Info, !IO).
+    % Read in results and requests for the module being analysed.
+    load_module_analysis_results(ThisModule, !Info, !IO),
+    read_module_analysis_requests(!.Info, ThisModule, ThisModuleRequests, !IO),
+    !Info ^ analysis_requests ^ elem(ThisModule) := ThisModuleRequests.
 
-:- pred ensure_old_module_analysis_results_loaded(module_name::in,
+:- pred load_module_analysis_results(module_name::in,
     analysis_info::in, analysis_info::out, io::di, io::uo) is det.
 
-ensure_old_module_analysis_results_loaded(ModuleName, !Info, !IO) :-
-    ( map.search(!.Info ^ old_analysis_results, ModuleName, _Results) ->
-        % sanity check
-        map.lookup(!.Info ^ module_statuses, ModuleName, _StatusMustExist)
+load_module_analysis_results(ModuleName, !Info, !IO) :-
+    (
+        ( map.contains(!.Info ^ old_analysis_results, ModuleName)
+        ; map.contains(!.Info ^ module_statuses, ModuleName)
+        )
+    ->
+        unexpected(this_file, "ensure_old_module_analysis_results_loaded")
     ;
         analysis.read_module_overall_status(!.Info ^ compiler, ModuleName,
             ModuleStatus, !IO),
@@ -1011,20 +1208,6 @@ ensure_old_module_analysis_results_loade
         !Info ^ old_analysis_results ^ elem(ModuleName) := ModuleResults
     ).
 
-:- pred ensure_old_imdg_loaded(module_name::in, analysis_info::in,
-    analysis_info::out, io::di, io::uo) is det.
-
-ensure_old_imdg_loaded(ModuleName, !Info, !IO) :-
-    Map0 = !.Info ^ old_imdg,
-    ( map.search(Map0, ModuleName, _) ->
-        % already loaded
-        true
-    ;
-        read_module_imdg(!.Info, ModuleName, IMDG, !IO),
-        map.det_insert(Map0, ModuleName, IMDG, Map),
-        !Info ^ old_imdg := Map
-    ).
-
 module_is_local(Info, ModuleName, IsLocal) :-
     ( set.contains(Info ^ local_module_names, ModuleName) ->
         IsLocal = yes
@@ -1038,96 +1221,97 @@ module_is_local(Info, ModuleName, IsLoca
     % and will write out data currently cached in the analysis_info structure
     % out to disk.
     %
-write_analysis_files(Compiler, ModuleInfo, ModuleName, ImportedModuleNames,
-        !Info, !IO) :-
-    % The current module was just compiled so we set its status to the
-    % lub of all the new analysis results generated.
-    ( map.search(!.Info ^ new_analysis_results, ModuleName, NewResults) ->
-        ModuleStatus = lub_result_statuses(NewResults)
-    ; 
-        ModuleStatus = optimal,
-        % Force an `.analysis' file to be written out for this module,
-        % even though there are no results recorded for it.
-        !Info ^ new_analysis_results ^ elem(ModuleName) := map.init
-    ),
+write_analysis_files(Compiler, ModuleInfo, ImportedModule0, !Info, !IO) :-
+    ThisModule = !.Info ^ this_module,
+    ImportedModules = set.delete(ImportedModule0, ThisModule),
+
+    LocalModules = !.Info ^ local_module_names,
+    LocalImportedModules = set.intersect(LocalModules, ImportedModules),
+
+    % Load IMDG files for local modules.
+    set.fold2(load_module_imdg, LocalModules, !Info, !IO),
 
     update_analysis_registry(ModuleInfo, !Info, !IO),
 
-    !Info ^ module_statuses ^ elem(ModuleName) := ModuleStatus,
+    % The current module was just compiled so we set its status to the
+    % lub of all the new analysis results generated.
+    ModuleStatus = lub_result_statuses(!.Info ^ new_analysis_results),
+    !Info ^ module_statuses ^ elem(ThisModule) := ModuleStatus,
 
-    update_intermodule_dependencies(ModuleName, ImportedModuleNames, !Info),
+    update_intermodule_dependencies(ThisModule, LocalImportedModules, !Info),
     ( map.is_empty(!.Info ^ new_analysis_results) ->
         true
     ;
-        io.print("Warning: new_analysis_results is not empty\n",
-            !IO),
-        io.print(!.Info ^ new_analysis_results, !IO),
-        io.nl(!IO)
+        unexpected(this_file,
+            "write_analysis_files: new_analysis_results is not empty")
     ),
 
-    % 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.
-    write_local_modules(!.Info, write_module_status_and_analysis_results,
-        !.Info ^ old_analysis_results, !IO),
-
-    % Write the requests for the imported modules.
-    write_local_modules(!.Info, write_module_analysis_requests,
-        !.Info ^ analysis_requests, !IO),
+    % Write the module statuses for all local modules (not necessarily
+    % imported).
+    set.fold(maybe_write_module_overall_status(!.Info), LocalModules, !IO),
+
+    % Write the analysis results for the current module.
+    ModuleResults = !.Info ^ old_analysis_results ^ det_elem(ThisModule),
+    write_module_analysis_results(!.Info, ThisModule, ModuleResults, !IO),
+
+    % Write the requests for imported local modules.
+    set.fold(maybe_write_module_requests(!.Info), LocalImportedModules, !IO),
 
     % Remove the requests for the current module since we (should have)
     % fulfilled them in this pass.
-    empty_request_file(!.Info, ModuleName, !IO),
+    empty_request_file(!.Info, ThisModule, !IO),
 
     % Write the intermodule dependency graphs.
-    write_local_modules(!.Info, write_module_imdg, !.Info ^ old_imdg, !IO),
+    set.fold(maybe_write_module_imdg(!.Info), LocalImportedModules, !IO),
 
     % Touch a timestamp file to indicate the last time that this module was
     % analysed.
-    module_name_to_write_file_name(Compiler, ModuleName, ".analysis_date",
+    module_name_to_write_file_name(Compiler, ThisModule, ".analysis_date",
         TimestampFileName, !IO),
     touch_datestamp(TimestampFileName, !IO).
 
-:- type write_module_analysis_map(T) ==
-    (pred(analysis_info, module_name, 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.
-
-write_local_modules(Info, Write, AnalysisMap, !IO) :-
-    map.foldl(write_local_modules_2(Info, Write), AnalysisMap, !IO).
-
-:- pred write_local_modules_2(analysis_info::in,
-    write_module_analysis_map(T)::write_module_analysis_map,
-    module_name::in, module_analysis_map(T)::in, io::di, io::uo) is det.
+:- pred load_module_imdg(module_name::in,
+    analysis_info::in, analysis_info::out, io::di, io::uo) is det.
 
-write_local_modules_2(Info, Write, ModuleName, ModuleResults, !IO) :-
-    module_is_local(Info, ModuleName, IsLocal),
-    (
-        IsLocal = yes,
-        Write(Info, ModuleName, ModuleResults, !IO)
+load_module_imdg(ModuleName, !Info, !IO) :-
+    read_module_imdg(!.Info, ModuleName, IMDG, !IO),
+    Map0 = !.Info ^ old_imdg,
+    map.det_insert(Map0, ModuleName, IMDG, Map),
+    !Info ^ old_imdg := Map.
+
+:- pred maybe_write_module_overall_status(analysis_info::in, module_name::in,
+    io::di, io::uo) is det.
+
+maybe_write_module_overall_status(Info, ModuleName, !IO) :-
+    ( map.search(Info ^ module_statuses, ModuleName, Status) ->
+        analysis.file.write_module_overall_status(Info, ModuleName, Status,
+            !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(ModuleName, !IO),
-            io.nl(!IO)
-        ), !IO)
+        % We didn't have any reason to read in the status of this module
+        % so we have no reason to touch it either.
+        true
     ).
 
-:- pred write_module_status_and_analysis_results(analysis_info::in,
-    module_name::in, module_analysis_map(some_analysis_result)::in,
+:- pred maybe_write_module_requests(analysis_info::in, module_name::in,
     io::di, io::uo) is det.
 
-write_module_status_and_analysis_results(Info, ModuleName, ModuleResults,
-        !IO) :-
-    ModuleStatus = Info ^ module_statuses ^ det_elem(ModuleName),
-    analysis.file.write_module_overall_status(Info, ModuleName,
-        ModuleStatus, !IO),
-    analysis.file.write_module_analysis_results(Info, ModuleName,
-        ModuleResults, !IO).
+maybe_write_module_requests(Info, ModuleName, !IO) :-
+    ( map.search(Info ^ analysis_requests, ModuleName, Requests) ->
+        analysis.file.write_module_analysis_requests(Info, ModuleName,
+            Requests, !IO)
+    ;
+        true
+    ).
+
+:- pred maybe_write_module_imdg(analysis_info::in, module_name::in,
+    io::di, io::uo) is det.
+
+maybe_write_module_imdg(Info, ModuleName, !IO) :-
+    ( map.search(Info ^ old_imdg, ModuleName, ModuleEntries) ->
+        analysis.file.write_module_imdg(Info, ModuleName, ModuleEntries, !IO)
+    ;
+        true
+    ).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/exception_analysis.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/exception_analysis.m,v
retrieving revision 1.47
diff -u -p -r1.47 exception_analysis.m
--- compiler/exception_analysis.m	27 Mar 2008 02:29:41 -0000	1.47
+++ compiler/exception_analysis.m	3 Jun 2008 07:32:23 -0000
@@ -159,12 +159,16 @@ analyse_exceptions_in_module(!ModuleInfo
     module_info_dependency_info(!.ModuleInfo, DepInfo),
     hlds_dependency_info_get_dependency_ordering(DepInfo, SCCs),
     list.foldl(check_scc_for_exceptions, SCCs, !ModuleInfo),
-    % Only write exception analysis pragmas to `.opt' files for
-    % `--intermodule-optimization', not `--intermodule-analysis'.
+
     globals.io_lookup_bool_option(make_optimization_interface, MakeOptInt,
         !IO),
     globals.io_lookup_bool_option(intermodule_analysis, IntermodAnalysis,
         !IO),
+    globals.io_lookup_bool_option(make_analysis_registry, MakeAnalysisReg,
+        !IO),
+
+    % Only write exception analysis pragmas to `.opt' files for
+    % `--intermodule-optimization', not `--intermodule-analysis'.
     (
         MakeOptInt = yes,
         IntermodAnalysis = no
@@ -172,6 +176,21 @@ analyse_exceptions_in_module(!ModuleInfo
         make_optimization_interface(!.ModuleInfo, !IO)
     ;
         true
+    ),
+
+    % Record results if making the analysis registry.  We do this in a
+    % separate pass so that we record results for exported `:- external'
+    % procedures, which don't get analysed because we don't have clauses
+    % for them.
+    (
+        MakeAnalysisReg = yes,
+        module_info_get_analysis_info(!.ModuleInfo, AnalysisInfo0),
+        module_info_predids(PredIds, !ModuleInfo),
+        list.foldl(maybe_record_exception_result(!.ModuleInfo),
+            PredIds, AnalysisInfo0, AnalysisInfo),
+        module_info_set_analysis_info(AnalysisInfo, !ModuleInfo)
+    ;
+        MakeAnalysisReg = no
     ).
 
 %----------------------------------------------------------------------------%
@@ -222,27 +241,7 @@ check_scc_for_exceptions(SCC, !ModuleInf
             proc_exception_info(Status, MaybeAnalysisStatus)
     ),
     list.foldl(Update, SCC, ExceptionInfo0, ExceptionInfo),
-    module_info_set_exception_info(ExceptionInfo, !ModuleInfo),
-    %
-    % Record the analysis results for intermodule analysis.
-    %
-    module_info_get_globals(!.ModuleInfo, Globals),
-    globals.lookup_bool_option(Globals, make_analysis_registry,
-        MakeAnalysisRegistry),
-    (
-        MakeAnalysisRegistry = yes,
-        (
-            MaybeAnalysisStatus = yes(AnalysisStatus),
-            record_exception_analysis_results(Status, AnalysisStatus, SCC,
-                !ModuleInfo)
-        ;
-            MaybeAnalysisStatus = no,
-            unexpected(this_file,
-                "check_scc_for_exceptions: no analysis status.")
-        )
-    ;
-        MakeAnalysisRegistry = no
-    ).
+    module_info_set_exception_info(ExceptionInfo, !ModuleInfo).
 
     % Check each procedure in the SCC individually.
     %
@@ -425,11 +424,10 @@ check_goal_for_exceptions_2(SCC, VarType
         check_vars(!.ModuleInfo, VarTypes, CallArgs, MaybeAnalysisStatus,
             !Result)
     ;
-        Imported = pred_to_bool(pred_info_is_imported(CallPredInfo)),
-        check_nonrecursive_call(SCC, VarTypes, CallPPId, CallArgs,
-            Imported, !Result, !ModuleInfo)
+        check_nonrecursive_call(VarTypes, CallPPId, CallArgs, CallPredInfo,
+            !Result, !ModuleInfo)
     ).
-check_goal_for_exceptions_2(SCC, VarTypes, Goal, GoalInfo, !Result,
+check_goal_for_exceptions_2(_SCC, VarTypes, Goal, GoalInfo, !Result,
         !ModuleInfo) :-
     Goal = generic_call(Details, Args, _ArgModes, _),
     module_info_get_globals(!.ModuleInfo, Globals),
@@ -439,7 +437,7 @@ check_goal_for_exceptions_2(SCC, VarType
         Details = higher_order(Var, _, _,  _),
         ClosureValueMap = goal_info_get_ho_values(GoalInfo),
         ( ClosureValues = ClosureValueMap ^ elem(Var) ->
-            get_closures_exception_status(IntermodAnalysis, SCC, ClosureValues,
+            get_closures_exception_status(IntermodAnalysis, ClosureValues,
                 MaybeWillNotThrow, MaybeAnalysisStatus, !ModuleInfo),
             (
                 MaybeWillNotThrow = maybe_will_not_throw(ConditionalProcs),
@@ -587,33 +585,33 @@ check_goals_for_exceptions(SCC, VarTypes
     % closure analysis), work out what the overall exception and analysis
     % status is going to be.
     %
-:- pred get_closures_exception_status(bool::in, scc::in, set(pred_proc_id)::in,
+:- pred get_closures_exception_status(bool::in, set(pred_proc_id)::in,
     closures_exception_status::out, maybe(analysis_status)::out,
     module_info::in, module_info::out) is det.
 
-get_closures_exception_status(IntermodAnalysis, SCC, Closures,
+get_closures_exception_status(IntermodAnalysis, Closures,
         Conditionals, AnalysisStatus, !ModuleInfo) :-
     module_info_get_exception_info(!.ModuleInfo, ExceptionInfo),
     AnalysisStatus0 = maybe_optimal(IntermodAnalysis),
     set.fold3(
-        get_closure_exception_status(IntermodAnalysis, SCC, ExceptionInfo),
+        get_closure_exception_status(IntermodAnalysis, ExceptionInfo),
         Closures, maybe_will_not_throw([]), Conditionals,
         AnalysisStatus0, AnalysisStatus, !ModuleInfo).
 
 :- pred get_closure_exception_status(
-    bool::in, scc::in, exception_info::in, pred_proc_id::in,
+    bool::in, exception_info::in, pred_proc_id::in,
     closures_exception_status::in, closures_exception_status::out,
     maybe(analysis_status)::in, maybe(analysis_status)::out,
     module_info::in, module_info::out) is det.
 
-get_closure_exception_status(IntermodAnalysis, SCC, ExceptionInfo, PPId,
+get_closure_exception_status(IntermodAnalysis, ExceptionInfo, PPId,
         !MaybeWillNotThrow, !AS, !ModuleInfo) :-
     module_info_pred_proc_info(!.ModuleInfo, PPId, PredInfo, _),
     (
         IntermodAnalysis = yes,
-        pred_info_is_imported(PredInfo)
+        pred_info_is_imported_not_external(PredInfo)
     ->
-        search_analysis_status(PPId, ExceptionStatus, AnalysisStatus, SCC,
+        search_analysis_status(PPId, ExceptionStatus, AnalysisStatus,
             !ModuleInfo),
         MaybeAnalysisStatus = yes(AnalysisStatus)
     ;
@@ -622,7 +620,7 @@ get_closure_exception_status(IntermodAna
                 MaybeAnalysisStatus)
         ;
             ExceptionStatus = may_throw(user_exception),
-            MaybeAnalysisStatus = maybe_suboptimal(IntermodAnalysis)
+            MaybeAnalysisStatus = maybe_optimal(IntermodAnalysis)
         )
     ),
     (
@@ -687,13 +685,12 @@ combine_maybe_analysis_status(MaybeStatu
 % Extra procedures for handling calls.
 %
 
-:- pred check_nonrecursive_call(scc::in, vartypes::in,
-    pred_proc_id::in, prog_vars::in, bool::in,
+:- pred check_nonrecursive_call(vartypes::in,
+    pred_proc_id::in, prog_vars::in, pred_info::in,
     proc_result::in, proc_result::out,
     module_info::in, module_info::out) is det.
 
-check_nonrecursive_call(SCC, VarTypes, PPId, Args, Imported, !Result,
-        !ModuleInfo) :-
+check_nonrecursive_call(VarTypes, PPId, Args, PredInfo, !Result, !ModuleInfo) :-
     module_info_get_globals(!.ModuleInfo, Globals),
     globals.lookup_bool_option(Globals, intermodule_analysis,
         IntermodAnalysis),
@@ -701,9 +698,9 @@ check_nonrecursive_call(SCC, VarTypes, P
         % If we are using `--intermodule-analysis' then use the analysis
         % framework for imported procedures.
         IntermodAnalysis = yes,
-        Imported = yes
+        pred_info_is_imported_not_external(PredInfo)
     ->
-        search_analysis_status(PPId, CalleeResult, AnalysisStatus, SCC,
+        search_analysis_status(PPId, CalleeResult, AnalysisStatus,
             !ModuleInfo),
         MaybeAnalysisStatus = yes(AnalysisStatus),
         update_proc_result(CalleeResult, MaybeAnalysisStatus, !Result)
@@ -728,7 +725,8 @@ check_nonrecursive_call(SCC, VarTypes, P
         ;
             % If we do not have any information about the callee procedure
             % then assume that it might throw an exception.
-            MaybeAnalysisStatus = maybe_suboptimal(IntermodAnalysis),
+            % Analysis statuses on individual results are meaningless now.
+            MaybeAnalysisStatus = maybe_optimal(IntermodAnalysis),
             update_proc_result(may_throw(user_exception), MaybeAnalysisStatus,
                 !Result)
         )
@@ -1052,133 +1050,116 @@ exception_status_to_string(may_throw(use
 %
 
 :- pred search_analysis_status(pred_proc_id::in,
-    exception_status::out, analysis_status::out, scc::in,
+    exception_status::out, analysis_status::out,
     module_info::in, module_info::out) is det.
 
-search_analysis_status(PPId, Result, AnalysisStatus, CallerSCC, !ModuleInfo) :-
+search_analysis_status(PPId, Result, AnalysisStatus, !ModuleInfo) :-
     module_info_get_analysis_info(!.ModuleInfo, AnalysisInfo0),
     search_analysis_status_2(!.ModuleInfo, PPId, Result, AnalysisStatus,
-        CallerSCC, AnalysisInfo0, AnalysisInfo),
+        AnalysisInfo0, AnalysisInfo),
     module_info_set_analysis_info(AnalysisInfo, !ModuleInfo).
 
 :- pred search_analysis_status_2(module_info::in, pred_proc_id::in,
-    exception_status::out, analysis_status::out, scc::in,
+    exception_status::out, analysis_status::out,
     analysis_info::in, analysis_info::out) is det.
 
-search_analysis_status_2(ModuleInfo, PPId, Result, AnalysisStatus, CallerSCC,
+search_analysis_status_2(ModuleInfo, PPId, Result, AnalysisStatus,
         !AnalysisInfo) :-
     module_name_func_id(ModuleInfo, PPId, ModuleName, FuncId),
     Call = any_call,
     lookup_best_result(!.AnalysisInfo, ModuleName, FuncId, no_func_info, Call,
         MaybeBestResult),
-    module_info_get_globals(ModuleInfo, Globals),
-    globals.lookup_bool_option(Globals, make_analysis_registry,
-        MakeAnalysisRegistry),
     (
         MaybeBestResult = yes(analysis_result(BestCall, BestAnswer,
             AnalysisStatus)),
         BestAnswer = exception_analysis_answer(Result),
-        (
-            MakeAnalysisRegistry = yes,
-            record_dependencies(ModuleName, FuncId, BestCall, ModuleInfo,
-                CallerSCC, !AnalysisInfo)
-        ;
-            MakeAnalysisRegistry = no
-        )
+        record_dependency(ModuleName, FuncId, no_func_info, BestCall,
+            _ : exception_analysis_answer, !AnalysisInfo)
     ;
         MaybeBestResult = no,
         % If we do not have any information about the callee procedure then
         % assume that it throws an exception.
         top(no_func_info, Call) = Answer,
         Answer = exception_analysis_answer(Result),
-        module_is_local(!.AnalysisInfo, ModuleName, IsLocal),
-        (
-            IsLocal = yes,
-            AnalysisStatus = suboptimal,
-            (
-                MakeAnalysisRegistry = yes,
-                analysis.record_result(ModuleName, FuncId,
-                    Call, Answer, AnalysisStatus, !AnalysisInfo),
-                analysis.record_request(analysis_name, ModuleName, FuncId,
-                    Call, !AnalysisInfo),
-                record_dependencies(ModuleName, FuncId, Call,
-                    ModuleInfo, CallerSCC, !AnalysisInfo)
-            ;
-                MakeAnalysisRegistry = no
-            )
-        ;
-            IsLocal = no,
-            % We can't do any better anyway.
-            AnalysisStatus = optimal
-        )
+        AnalysisStatus = optimal,
+        record_request(analysis_name, ModuleName,  FuncId, Call, !AnalysisInfo)
     ).
 
-    % XXX If the procedures in CallerSCC definitely come from the
-    % same module then we don't need to record the dependency so many
-    % times, at least while we only have module-level granularity.
-    %
-:- pred record_dependencies(module_name::in, func_id::in, Call::in,
-    module_info::in, scc::in, analysis_info::in, analysis_info::out)
-    is det <= call_pattern(FuncInfo, Call).
-
-record_dependencies(ModuleName, FuncId, Call,
-        ModuleInfo, CallerSCC, !AnalysisInfo) :-
-    list.foldl((pred(CallerPPId::in, Info0::in, Info::out) is det :-
-        module_name_func_id(ModuleInfo, CallerPPId, CallerModuleName, _),
-        record_dependency(CallerModuleName, analysis_name, ModuleName, FuncId,
-            Call, Info0, Info)
-    ), CallerSCC, !AnalysisInfo).
-
-:- pred record_exception_analysis_results(exception_status::in,
-    analysis_status::in, scc::in, module_info::in, module_info::out) is det.
+:- pred maybe_record_exception_result(module_info::in, pred_id::in,
+    analysis_info::in, analysis_info::out) is det.
 
-record_exception_analysis_results(Status, ResultStatus, SCC, !ModuleInfo) :-
-    module_info_get_analysis_info(!.ModuleInfo, AnalysisInfo0),
-    list.foldl(
-        record_exception_analysis_result(!.ModuleInfo, Status, ResultStatus),
-        SCC, AnalysisInfo0, AnalysisInfo),
-    module_info_set_analysis_info(AnalysisInfo, !ModuleInfo).
+maybe_record_exception_result(ModuleInfo, PredId, !AnalysisInfo) :-
+    module_info_pred_info(ModuleInfo, PredId, PredInfo),
+    ProcIds = pred_info_procids(PredInfo),
+    list.foldl(maybe_record_exception_result_2(ModuleInfo, PredId, PredInfo),
+        ProcIds, !AnalysisInfo).
 
-:- pred record_exception_analysis_result(module_info::in, exception_status::in,
-    analysis_status::in, pred_proc_id::in,
-    analysis_info::in, analysis_info::out) is det.
+:- pred maybe_record_exception_result_2(module_info::in, pred_id::in,
+    pred_info::in, proc_id::in, analysis_info::in, analysis_info::out) is det.
 
-record_exception_analysis_result(ModuleInfo, Status, ResultStatus, PPId,
+maybe_record_exception_result_2(ModuleInfo, PredId, PredInfo, ProcId,
         !AnalysisInfo) :-
-    PPId = proc(PredId, _ProcId),
-    module_info_pred_info(ModuleInfo, PredId, PredInfo),
-    should_write_exception_info(ModuleInfo, PredId, PredInfo, ShouldWrite),
+    should_write_exception_info(ModuleInfo, PredId, ProcId, PredInfo,
+        for_analysis_framework, ShouldWrite),
     (
         ShouldWrite = yes,
+        PPId = proc(PredId, ProcId),
+        module_info_get_exception_info(ModuleInfo, ExceptionInfo),
+        lookup_proc_exception_info(ExceptionInfo, PPId, Status, ResultStatus),
         module_name_func_id(ModuleInfo, PPId, ModuleName, FuncId),
-        Answer = exception_analysis_answer(Status),
-        record_result(ModuleName, FuncId, any_call, Answer, ResultStatus,
-            !AnalysisInfo)
+        record_result(ModuleName, FuncId, any_call,
+            exception_analysis_answer(Status), ResultStatus, !AnalysisInfo)
     ;
         ShouldWrite = no
     ).
 
-:- pred should_write_exception_info(module_info::in, pred_id::in,
-        pred_info::in, bool::out) is det.
+:- pred lookup_proc_exception_info(exception_info::in, pred_proc_id::in,
+    exception_status::out, analysis_status::out) is det.
+
+lookup_proc_exception_info(ExceptionInfo, PPId, Status, ResultStatus) :-
+    ( map.search(ExceptionInfo, PPId, ProcExceptionInfo) ->
+        ProcExceptionInfo = proc_exception_info(Status, MaybeResultStatus),
+        (
+            MaybeResultStatus = yes(ResultStatus)
+        ;
+            MaybeResultStatus = no,
+            unexpected(this_file,
+                "lookup_proc_exception_info: no result status")
+        )
+    ;
+        % Probably an exported `:- external' procedure.
+        Status = may_throw(user_exception),
+        ResultStatus = optimal
+    ).
+
+:- type should_write_for
+    --->    for_analysis_framework
+    ;       for_pragma.
 
-should_write_exception_info(ModuleInfo, PredId, PredInfo, ShouldWrite) :-
-    pred_info_get_import_status(PredInfo, ImportStatus),
+:- pred should_write_exception_info(module_info::in, pred_id::in, proc_id::in,
+    pred_info::in, should_write_for::in, bool::out) is det.
+
+should_write_exception_info(ModuleInfo, PredId, ProcId, PredInfo,
+        WhatFor, ShouldWrite) :-
     (
-        ( ImportStatus = status_exported
-        ; ImportStatus = status_opt_exported
-        ),
+        procedure_is_exported(ModuleInfo, PredInfo, ProcId),
         not is_unify_or_compare_pred(PredInfo),
-        module_info_get_type_spec_info(ModuleInfo, TypeSpecInfo),
-        TypeSpecInfo = type_spec_info(_, TypeSpecForcePreds, _, _),
-        not set.member(PredId, TypeSpecForcePreds),
-        %
-        % XXX Writing out pragmas for the automatically generated class
-        % instance methods causes the compiler to abort when it reads them
-        % back in.
-        %
-        pred_info_get_markers(PredInfo, Markers),
-        not check_marker(Markers, marker_class_instance_method),
-        not check_marker(Markers, marker_named_class_instance_method)
+        (
+            WhatFor = for_analysis_framework
+        ;
+            WhatFor = for_pragma,
+            module_info_get_type_spec_info(ModuleInfo, TypeSpecInfo),
+            TypeSpecInfo = type_spec_info(_, TypeSpecForcePreds, _, _),
+            not set.member(PredId, TypeSpecForcePreds),
+            %
+            % XXX Writing out pragmas for the automatically generated class
+            % instance methods causes the compiler to abort when it reads them
+            % back in.
+            %
+            pred_info_get_markers(PredInfo, Markers),
+            not check_marker(Markers, marker_class_instance_method),
+            not check_marker(Markers, marker_named_class_instance_method)
+        )
     ->
         ShouldWrite = yes
     ;
@@ -1190,11 +1171,6 @@ should_write_exception_info(ModuleInfo, 
 maybe_optimal(no)  = no.
 maybe_optimal(yes) = yes(optimal).
 
-:- func maybe_suboptimal(bool) = maybe(analysis_status).
-
-maybe_suboptimal(no)  = no.
-maybe_suboptimal(yes) = yes(suboptimal).
-
 %----------------------------------------------------------------------------%
 %
 % Stuff for intermodule optimization.
@@ -1233,26 +1209,32 @@ make_optimization_interface(ModuleInfo, 
 
 write_pragma_exceptions(ModuleInfo, ExceptionInfo, PredId, !IO) :-
     module_info_pred_info(ModuleInfo, PredId, PredInfo),
-    should_write_exception_info(ModuleInfo, PredId, PredInfo, ShouldWrite),
+    ProcIds = pred_info_procids(PredInfo),
+    list.foldl(
+        write_pragma_exceptions_2(ModuleInfo, ExceptionInfo, PredId, PredInfo), 
+        ProcIds, !IO).
+
+:- pred write_pragma_exceptions_2(module_info::in, exception_info::in,
+    pred_id::in, pred_info::in, proc_id::in, io::di, io::uo) is det.
+
+write_pragma_exceptions_2(ModuleInfo, ExceptionInfo, PredId, PredInfo, ProcId,
+        !IO) :-
+    should_write_exception_info(ModuleInfo, PredId, ProcId, PredInfo,
+        for_pragma, ShouldWrite),
     (
         ShouldWrite = yes,
         ModuleName = pred_info_module(PredInfo),
         Name       = pred_info_name(PredInfo),
         Arity      = pred_info_orig_arity(PredInfo),
         PredOrFunc = pred_info_is_pred_or_func(PredInfo),
-        ProcIds    = pred_info_procids(PredInfo),
-        list.foldl((pred(ProcId::in, !.IO::di, !:IO::uo) is det :-
-            proc_id_to_int(ProcId, ModeNum),
-            (
-                map.search(ExceptionInfo, proc(PredId, ProcId),
-                    ProcExceptionInfo)
-            ->
-                ProcExceptionInfo = proc_exception_info(Status, _),
-                mercury_output_pragma_exceptions(PredOrFunc,
-                    qualified(ModuleName, Name), Arity, ModeNum, Status, !IO)
-            ;
-                true
-            )), ProcIds, !IO)
+        proc_id_to_int(ProcId, ModeNum),
+        ( map.search(ExceptionInfo, proc(PredId, ProcId), ProcExceptionInfo) ->
+            ProcExceptionInfo = proc_exception_info(Status, _),
+            mercury_output_pragma_exceptions(PredOrFunc,
+                qualified(ModuleName, Name), Arity, ModeNum, Status, !IO)
+        ;
+            true
+        )
     ;
         ShouldWrite = no
     ).
@@ -1265,7 +1247,7 @@ write_pragma_exceptions(ModuleInfo, Exce
 lookup_exception_analysis_result(PPId, ExceptionStatus, !ModuleInfo) :-
     PPId = proc(PredId, _),
     module_info_pred_info(!.ModuleInfo, PredId, PredInfo),
-    IsImported = pred_to_bool(pred_info_is_imported(PredInfo)),
+    IsImported = pred_to_bool(pred_info_is_imported_not_external(PredInfo)),
     module_info_get_globals(!.ModuleInfo, Globals),
     globals.lookup_bool_option(Globals, intermodule_analysis,
         IntermodAnalysis),
@@ -1312,9 +1294,8 @@ lookup_exception_analysis_result(PPId, E
                 MaybeBestResult = no,
                 ExceptionStatus = may_throw(user_exception)
             ),
-            module_info_get_name(!.ModuleInfo, ThisModuleName),
-            record_dependency(ThisModuleName, analysis_name,
-                ModuleName, FuncId, any_call, !AnalysisInfo),
+            record_dependency(ModuleName, FuncId, no_func_info, any_call,
+                _ : exception_analysis_answer, !AnalysisInfo),
             module_info_set_analysis_info(!.AnalysisInfo, !ModuleInfo)
         )
     ).
Index: compiler/hlds_module.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/hlds_module.m,v
retrieving revision 1.158
diff -u -p -r1.158 hlds_module.m
--- compiler/hlds_module.m	28 May 2008 00:52:27 -0000	1.158
+++ compiler/hlds_module.m	3 Jun 2008 07:32:23 -0000
@@ -49,6 +49,7 @@
 
 :- implementation.
 
+:- import_module libs.options.
 :- import_module transform_hlds.mmc_analysis.
 :- import_module parse_tree.modules.
 
@@ -869,7 +870,11 @@ module_info_init(Name, Items, Globals, Q
 
     MaybeComplexityMap = no,
     ComplexityProcInfos = [],
-    AnalysisInfo = init_analysis_info(mmc),
+
+    globals.lookup_bool_option(Globals, make_analysis_registry,
+        MakeAnalysisReg),
+    AnalysisInfo = init_analysis_info(mmc, Name, MakeAnalysisReg),
+
     UserInitPredCNames = [],
     UserFinalPredCNames = [],
     set.init(StructureReusePredIds),
Index: compiler/hlds_pred.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/hlds_pred.m,v
retrieving revision 1.243
diff -u -p -r1.243 hlds_pred.m
--- compiler/hlds_pred.m	7 May 2008 05:05:51 -0000	1.243
+++ compiler/hlds_pred.m	3 Jun 2008 07:32:24 -0000
@@ -724,6 +724,8 @@
 
 :- pred pred_info_is_imported(pred_info::in) is semidet.
 
+:- pred pred_info_is_imported_not_external(pred_info::in) is semidet.
+
 :- pred pred_info_is_pseudo_imported(pred_info::in) is semidet.
 
     % pred_info_is_exported does *not* include predicates which are
@@ -1396,6 +1398,10 @@ pred_info_is_imported(PredInfo) :-
     ; Status = status_external(_)
     ).
 
+pred_info_is_imported_not_external(PredInfo) :-
+    pred_info_get_import_status(PredInfo, Status),
+    Status = status_imported(_).
+
 pred_info_is_pseudo_imported(PredInfo) :-
     pred_info_get_import_status(PredInfo, ImportStatus),
     ImportStatus = status_pseudo_imported.
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.471
diff -u -p -r1.471 mercury_compile.m
--- compiler/mercury_compile.m	2 Jun 2008 02:27:27 -0000	1.471
+++ compiler/mercury_compile.m	3 Jun 2008 07:32:24 -0000
@@ -1522,7 +1522,7 @@ mercury_compile(Module, NestedSubModules
             FactTableObjFiles = []
         ; MakeAnalysisRegistry = yes ->
             prepare_intermodule_analysis(HLDS21, HLDS22, !IO),
-            output_analysis_file(ModuleName, HLDS22, !DumpInfo, !IO),
+            output_analysis_file(HLDS22, !DumpInfo, !IO),
             FactTableObjFiles = []
         ; MakeXmlDocumentation = yes ->
             xml_documentation(HLDS21, !IO),
@@ -1561,9 +1561,7 @@ maybe_prepare_intermodule_analysis(!HLDS
     io::di, io::uo) is det.
 
 prepare_intermodule_analysis(!HLDS, !IO) :-
-    module_info_get_name(!.HLDS, ThisModuleName),
-    module_info_get_all_deps(!.HLDS, ModuleNames0),
-    set.insert(ModuleNames0, ThisModuleName, ModuleNames),
+    module_info_get_all_deps(!.HLDS, ModuleNames),
 
     globals.io_lookup_accumulating_option(local_module_id, LocalModulesList,
         !IO),
@@ -1571,8 +1569,8 @@ prepare_intermodule_analysis(!HLDS, !IO)
     LocalModuleNames = set.from_list(SymNames),
 
     module_info_get_analysis_info(!.HLDS, AnalysisInfo0),
-    analysis.prepare_intermodule_analysis(ThisModuleName, ModuleNames,
-        LocalModuleNames, AnalysisInfo0, AnalysisInfo, !IO),
+    analysis.prepare_intermodule_analysis(ModuleNames, LocalModuleNames,
+        AnalysisInfo0, AnalysisInfo, !IO),
     module_info_set_analysis_info(AnalysisInfo, !HLDS).
 
 :- pred mercury_compile_after_front_end(list(module_name)::in,
@@ -2447,10 +2445,10 @@ output_trans_opt_file(!.HLDS, !DumpInfo,
     maybe_dump_hlds(!.HLDS, 185, "mm_tabling_analysis", !DumpInfo, !IO),
     write_trans_opt_file(!.HLDS, !IO).
 
-:- pred output_analysis_file(module_name::in, module_info::in,
+:- pred output_analysis_file(module_info::in,
     dump_info::in, dump_info::out, io::di, io::uo) is det.
 
-output_analysis_file(ModuleName, !.HLDS, !DumpInfo, !IO) :-
+output_analysis_file(!.HLDS, !DumpInfo, !IO) :-
     module_info_get_globals(!.HLDS, Globals),
     globals.lookup_bool_option(Globals, verbose, Verbose),
     globals.lookup_bool_option(Globals, statistics, Stats),
@@ -2504,7 +2502,7 @@ output_analysis_file(ModuleName, !.HLDS,
 
     module_info_get_analysis_info(!.HLDS, AnalysisInfo),
     module_info_get_all_deps(!.HLDS, ImportedModules),
-    analysis.write_analysis_files(mmc, !.HLDS, ModuleName, ImportedModules,
+    analysis.write_analysis_files(mmc, !.HLDS, ImportedModules,
         AnalysisInfo, _AnalysisInfo, !IO).
 
 :- pred frontend_pass_by_phases(module_info::in, module_info::out,
Index: compiler/mmc_analysis.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/mmc_analysis.m,v
retrieving revision 1.24
diff -u -p -r1.24 mmc_analysis.m
--- compiler/mmc_analysis.m	7 May 2008 05:05:52 -0000	1.24
+++ compiler/mmc_analysis.m	3 Jun 2008 07:32:24 -0000
@@ -21,7 +21,6 @@
 :- import_module hlds.hlds_module.
 :- import_module hlds.hlds_pred.
 :- import_module mdbcomp.prim_data.
-:- import_module parse_tree.prog_data.
 
 %-----------------------------------------------------------------------------%
 
@@ -30,12 +29,12 @@
 
 :- instance compiler(mmc).
 
-:- func pred_or_func_name_arity_to_func_id(pred_or_func, string, arity,
-    proc_id) = func_id.
-
 :- pred module_name_func_id(module_info::in, pred_proc_id::in,
     module_name::out, func_id::out) is det.
 
+:- pred module_name_func_id_from_pred_info(pred_info::in, proc_id::in,
+    module_name::out, func_id::out) is det.
+
 :- pred func_id_to_ppid(module_info::in, module_name::in,
     func_id::in, pred_proc_id::out) is det.
 
@@ -49,6 +48,7 @@
 :- import_module libs.globals.
 :- import_module libs.options.
 :- import_module parse_tree.modules.
+:- import_module parse_tree.prog_data.
 :- import_module parse_tree.prog_io.
 :- import_module parse_tree.prog_out.
 :- import_module transform_hlds.ctgc.
@@ -131,11 +131,11 @@ mmc_module_name_to_read_file_name(Module
 mmc_module_name_to_write_file_name(ModuleName, Ext, FileName, !IO) :-
     module_name_to_file_name(ModuleName, Ext, yes, FileName, !IO).
 
-pred_or_func_name_arity_to_func_id(PredOrFunc, Name, Arity, ProcId) =
-    func_id(PredOrFunc, Name, Arity, ProcId).
-
 module_name_func_id(ModuleInfo, proc(PredId, ProcId), PredModule, FuncId) :-
     module_info_pred_info(ModuleInfo, PredId, PredInfo),
+    module_name_func_id_from_pred_info(PredInfo, ProcId, PredModule, FuncId).
+
+module_name_func_id_from_pred_info(PredInfo, ProcId, PredModule, FuncId) :-
     PredModule = pred_info_module(PredInfo),
     PredName = pred_info_name(PredInfo),
     PredOrFunc = pred_info_is_pred_or_func(PredInfo),
@@ -152,8 +152,7 @@ func_id_to_ppid(ModuleInfo, ModuleName, 
     ->
         PPId = proc(PredId, ProcId)
     ;
-        unexpected(this_file,
-            "func_id_to_ppid: more than one predicate")
+        unexpected(this_file, "func_id_to_ppid: more than one predicate")
     ).
 
 %-----------------------------------------------------------------------------%
Index: compiler/structure_reuse.analysis.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/structure_reuse.analysis.m,v
retrieving revision 1.14
diff -u -p -r1.14 structure_reuse.analysis.m
--- compiler/structure_reuse.analysis.m	28 May 2008 00:52:29 -0000	1.14
+++ compiler/structure_reuse.analysis.m	3 Jun 2008 07:32:24 -0000
@@ -93,6 +93,7 @@
 :- implementation.
 
 :- import_module check_hlds.goal_path.
+:- import_module hlds.hlds_out.
 :- import_module hlds.passes_aux.
 :- import_module hlds.pred_table.
 :- import_module libs.compiler_util.
@@ -264,8 +265,9 @@ structure_reuse_analysis(!ModuleInfo, !I
     % remove them if they were created from exported procedures (so would be
     % exported themselves). 
     module_info_get_predicate_table(!.ModuleInfo, PredTable0),
-    map.foldl(remove_useless_reuse_proc(ReuseInfoMap), ReuseVersionMap,
-        PredTable0, PredTable),
+    map.foldl(
+        remove_useless_reuse_proc(!.ModuleInfo, VeryVerbose, ReuseInfoMap),
+        ReuseVersionMap, PredTable0, PredTable),
     module_info_set_predicate_table(PredTable, !ModuleInfo).
 
 %-----------------------------------------------------------------------------%
@@ -601,21 +603,21 @@ process_intermod_analysis_defined_proc(M
     module_info_get_analysis_info(ModuleInfo, AnalysisInfo),
     module_name_func_id(ModuleInfo, PPId, ModuleName, FuncId),
 
-    % Add requests corresponding to the call patterns of existing answers.
-    lookup_results(AnalysisInfo, ModuleName, FuncId,
-        Results : list(analysis_result(structure_reuse_call, _))),
-    list.foldl(add_reuse_request_for_answer(PPId), Results, !ExternalRequests),
-
-    % Add new requests from other modules.
-    lookup_requests(AnalysisInfo, analysis_name, ModuleName, FuncId, Calls),
-    list.foldl(add_reuse_request(PPId), Calls, !ExternalRequests).
-
-:- pred add_reuse_request_for_answer(pred_proc_id::in,
-    analysis_result(structure_reuse_call, structure_reuse_answer)::in,
-    list(sr_request)::in, list(sr_request)::out) is det.
-
-add_reuse_request_for_answer(PPId, Result, !ExternalRequests) :-
-    add_reuse_request(PPId, Result ^ ar_call, !ExternalRequests).
+    % Only add requests for procedures that *really* belong to this module.
+    module_info_get_name(ModuleInfo, ThisModule),
+    ( ThisModule = ModuleName ->
+        % Add requests corresponding to the call patterns of existing answers.
+        lookup_existing_call_patterns(AnalysisInfo, analysis_name, ModuleName,
+            FuncId, OldCalls),
+        list.foldl(add_reuse_request(PPId), OldCalls, !ExternalRequests),
+
+        % Add new requests from other modules.
+        lookup_requests(AnalysisInfo, analysis_name, ModuleName, FuncId,
+            NewCalls),
+        list.foldl(add_reuse_request(PPId), NewCalls, !ExternalRequests)
+    ;
+        true
+    ).
 
 :- pred add_reuse_request(pred_proc_id::in, structure_reuse_call::in,
     list(sr_request)::in, list(sr_request)::out) is det.
@@ -712,7 +714,7 @@ write_pred_reuse_info(ModuleInfo, PredId
 write_proc_reuse_info(ModuleInfo, PredId, PredInfo, ProcTable, PredOrFunc,
         SymName, Context, TypeVarSet, ProcId, !IO) :-
     should_write_reuse_info(ModuleInfo, PredId, ProcId, PredInfo,
-        disallow_type_spec_preds, ShouldWrite),
+        for_pragma, ShouldWrite),
     (
         ShouldWrite = yes,
         map.lookup(ProcTable, ProcId, ProcInfo),
@@ -937,7 +939,7 @@ record_structure_reuse_results_2(ModuleI
 
     module_info_pred_info(ModuleInfo, PredId, PredInfo),
     should_write_reuse_info(ModuleInfo, PredId, ProcId, PredInfo,
-        allow_type_spec_preds, ShouldWrite),
+        for_analysis_framework, ShouldWrite),
     (
         ShouldWrite = yes,
         ( reuse_as_no_reuses(ReuseAs) ->
@@ -968,34 +970,13 @@ record_structure_reuse_results_2(ModuleI
 handle_structure_reuse_dependency(ModuleInfo,
         ppid_no_clobbers(DepPPId, NoClobbers), !AnalysisInfo) :-
     % Record that we depend on the result for the called procedure.
-    module_info_get_name(ModuleInfo, ThisModuleName),
     module_name_func_id(ModuleInfo, DepPPId, DepModuleName, DepFuncId),
     Call = structure_reuse_call(NoClobbers),
-    record_dependency(ThisModuleName, analysis_name, DepModuleName, DepFuncId,
-        Call, !AnalysisInfo),
-
-    % If the called procedure didn't have an answer in the analysis registry,
-    % record the assumed answer for it so that when it does get
-    % analysed, it will have something to compare against.
-    module_info_proc_info(ModuleInfo, DepPPId, ProcInfo),
-    FuncInfo = structure_reuse_func_info(ModuleInfo, ProcInfo),
-    lookup_matching_results(!.AnalysisInfo, DepModuleName, DepFuncId, FuncInfo,
-        Call, AnyResults : list(analysis_result(structure_reuse_call,
-            structure_reuse_answer))),
-    (
-        AnyResults = [],
-        Answer = bottom(FuncInfo, Call) : structure_reuse_answer,
-        % We assume an unknown answer is `optimal' otherwise we would not be
-        % able to get mutually recursive procedures out of the `suboptimal'
-        % state.
-        record_result(DepModuleName, DepFuncId, Call, Answer, optimal,
-            !AnalysisInfo),
-        % Record a request as well.
-        record_request(analysis_name, DepModuleName, DepFuncId, Call,
-            !AnalysisInfo)
-    ;
-        AnyResults = [_ | _]
-    ).
+    Answer = _ : structure_reuse_answer,
+    get_func_info(ModuleInfo, DepModuleName, DepFuncId, Call, Answer,
+        FuncInfo),
+    record_dependency(DepModuleName, DepFuncId, FuncInfo, Call, Answer,
+        !AnalysisInfo).
 
 :- pred record_intermod_requests(module_info::in, sr_request::in,
     analysis_info::in, analysis_info::out) is det.
@@ -1008,15 +989,15 @@ record_intermod_requests(ModuleInfo, sr_
 
 %-----------------------------------------------------------------------------%
 
-:- type allow_type_spec_preds
-    --->    allow_type_spec_preds
-    ;       disallow_type_spec_preds.
+:- type should_write_for
+    --->    for_analysis_framework
+    ;       for_pragma.
 
 :- pred should_write_reuse_info(module_info::in, pred_id::in, proc_id::in,
-    pred_info::in, allow_type_spec_preds::in, bool::out) is det.
+    pred_info::in, should_write_for::in, bool::out) is det.
 
-should_write_reuse_info(ModuleInfo, PredId, ProcId, PredInfo,
-        AllowTypeSpecPreds, ShouldWrite) :-
+should_write_reuse_info(ModuleInfo, PredId, ProcId, PredInfo, WhatFor,
+        ShouldWrite) :-
     (
         procedure_is_exported(ModuleInfo, PredInfo, ProcId),
         \+ is_unify_or_compare_pred(PredInfo),
@@ -1026,9 +1007,9 @@ should_write_reuse_info(ModuleInfo, Pred
         PredOrigin \= origin_transformed(transform_structure_reuse, _, _),
 
         (
-            AllowTypeSpecPreds = allow_type_spec_preds
+            WhatFor = for_analysis_framework
         ;
-            AllowTypeSpecPreds = disallow_type_spec_preds,
+            WhatFor = for_pragma,
             % XXX These should be allowed, but the predicate declaration for
             % the specialized predicate is not produced before the structure
             % reuse pragmas are read in, resulting in an undefined predicate
@@ -1045,17 +1026,30 @@ should_write_reuse_info(ModuleInfo, Pred
 
 %-----------------------------------------------------------------------------%
 
-:- pred remove_useless_reuse_proc(map(pred_proc_id, reuse_as_and_status)::in,
+:- pred remove_useless_reuse_proc(module_info::in, bool::in,
+    map(pred_proc_id, reuse_as_and_status)::in,
     ppid_no_clobbers::in, pred_proc_id::in,
     predicate_table::in, predicate_table::out) is det.
 
-remove_useless_reuse_proc(ReuseAsMap, _, PPId, !PredTable) :-
+remove_useless_reuse_proc(ModuleInfo, VeryVerbose, ReuseAsMap, _, PPId,
+        !PredTable) :-
     map.lookup(ReuseAsMap, PPId, ReuseAs_Status),
     ReuseAs_Status = reuse_as_and_status(ReuseAs, _),
     % XXX perhaps we can also remove reuse procedures with only unconditional
     % reuse?  Such a procedure should be the same as the "non-reuse" procedure
     % (which also implements any unconditional reuse).
     ( reuse_as_no_reuses(ReuseAs) ->
+        (
+            VeryVerbose = yes,
+            trace [io(!IO)] (
+                io.write_string("% Removing useless reuse ", !IO),
+                write_pred_proc_id(ModuleInfo, PPId, !IO),
+                io.nl(!IO)
+            )
+        ;
+            VeryVerbose = no
+        ),
+
         PPId = proc(PredId, _),
         % We can remove the whole predicate because we never generate
         % multi-moded reuse versions of predicates.
Index: compiler/structure_reuse.indirect.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/structure_reuse.indirect.m,v
retrieving revision 1.25
diff -u -p -r1.25 structure_reuse.indirect.m
--- compiler/structure_reuse.indirect.m	28 May 2008 00:52:29 -0000	1.25
+++ compiler/structure_reuse.indirect.m	3 Jun 2008 07:32:25 -0000
@@ -182,10 +182,6 @@ indirect_reuse_rerun_analyse_scc(Sharing
 :- pred extend_scc_with_reuse_procs(reuse_as_table::in, list(pred_proc_id)::in,
     list(pred_proc_id)::out) is det.
 
-% extend_scc_with_reuse_procs(_, SCC, SCC).
-
-% temporarily commented out to narrow down --structure-reuse-repeat bug
-
 extend_scc_with_reuse_procs(ReuseTable, SCC, ExtendedSCC) :-
     ReuseVersionMap = ReuseTable ^ reuse_version_map,
     solutions(
@@ -865,14 +861,10 @@ lookup_reuse_as(BaseInfo, OrigPPId, NoCl
     % If the called procedure was imported (not opt_imported) then remember
     % that this module depends on the results for that procedure.
     (
-        pred_info_get_import_status(BaseInfo ^ pred_info, PredImportStatus),
-        status_defined_in_this_module(PredImportStatus) = yes,
-
         OrigPPId = proc(CalleePredId, _),
         module_info_pred_info(BaseInfo ^ module_info, CalleePredId,
             CalleePredInfo),
-        pred_info_get_import_status(CalleePredInfo, CalleeImportStatus),
-        CalleeImportStatus = status_imported(_),
+        pred_info_is_imported_not_external(CalleePredInfo),
         \+ is_unify_or_compare_pred(CalleePredInfo)
     ->
         Dep = ppid_no_clobbers(OrigPPId, NoClobbers),
@@ -950,7 +942,13 @@ maybe_add_request(BaseInfo, CalleePPId, 
     ModuleInfo = BaseInfo ^ module_info,
     module_info_pred_info(ModuleInfo, CalleePredId, PredInfo),
     pred_info_get_import_status(PredInfo, ImportStatus),
-    ( status_defined_in_this_module(ImportStatus) = yes ->
+    (
+        (
+            status_defined_in_this_module(ImportStatus) = yes
+        ;
+            ImportStatus = status_opt_imported
+        )
+    ->
         Request = sr_request(CalleePPId, NotDeadArgNums),
         !IrInfo ^ requests := set.insert(!.IrInfo ^ requests, Request)
     ;
Index: compiler/structure_sharing.analysis.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/structure_sharing.analysis.m,v
retrieving revision 1.35
diff -u -p -r1.35 structure_sharing.analysis.m
--- compiler/structure_sharing.analysis.m	28 May 2008 00:52:29 -0000	1.35
+++ compiler/structure_sharing.analysis.m	3 Jun 2008 07:32:25 -0000
@@ -240,8 +240,7 @@ process_intermod_analysis_imported_shari
     some [!PredTable] (
         module_info_preds(!.ModuleInfo, !:PredTable),
         PredInfo0 = !.PredTable ^ det_elem(PredId),
-        pred_info_get_import_status(PredInfo0, ImportStatus),
-        ( ImportStatus = status_imported(_) ->
+        ( pred_info_is_imported_not_external(PredInfo0) ->
             module_info_get_analysis_info(!.ModuleInfo, AnalysisInfo),
             process_intermod_analysis_imported_sharing_in_procs(!.ModuleInfo,
                 AnalysisInfo, PredId, PredInfo0, PredInfo),
@@ -388,9 +387,9 @@ sharing_analysis(!ModuleInfo, !.SharingT
         MakeAnalysisRegistry = yes,
         some [!AnalysisInfo] (
             module_info_get_analysis_info(!.ModuleInfo, !:AnalysisInfo),
-            list.foldl(
-                record_sharing_analysis_results(!.ModuleInfo, !.SharingTable),
-                SCCs, !AnalysisInfo),
+            module_info_predids(PredIds, !ModuleInfo),
+            list.foldl(maybe_record_sharing_analysis_result(!.ModuleInfo,
+                !.SharingTable), PredIds, !AnalysisInfo),
             list.foldl(handle_dep_procs(!.ModuleInfo), DepProcs,
                 !AnalysisInfo),
             module_info_set_analysis_info(!.AnalysisInfo, !ModuleInfo)
@@ -572,8 +571,7 @@ analyse_goal(ModuleInfo, PredInfo, ProcI
             pred_info_get_import_status(PredInfo, PredImportStatus),
             status_defined_in_this_module(PredImportStatus) = yes,
             module_info_pred_info(ModuleInfo, CalleePredId, CalleePredInfo),
-            pred_info_get_import_status(CalleePredInfo, CalleeImportStatus),
-            CalleeImportStatus = status_imported(_),
+            pred_info_is_imported_not_external(CalleePredInfo),
             \+ is_unify_or_compare_pred(CalleePredInfo)
         ->
             !:DepProcs = [CalleePPId | !.DepProcs]
@@ -917,7 +915,7 @@ write_pred_sharing_info(ModuleInfo, Pred
 write_proc_sharing_info(ModuleInfo, PredId, PredInfo, ProcTable, PredOrFunc,
         SymName, Context, TypeVarSet, ProcId, !IO) :-
     should_write_sharing_info(ModuleInfo, PredId, ProcId, PredInfo,
-        disallow_type_spec_preds, ShouldWrite),
+        for_pragma, ShouldWrite),
     (
         ShouldWrite = yes,
 
@@ -1104,25 +1102,31 @@ sharing_answer_from_string(String) = Ans
 % Additional predicates used for intermodule analysis
 %
 
-:- pred record_sharing_analysis_results(module_info::in, sharing_as_table::in,
-    list(pred_proc_id)::in, analysis_info::in, analysis_info::out) is det.
+:- pred maybe_record_sharing_analysis_result(module_info::in,
+    sharing_as_table::in, pred_id::in, analysis_info::in, analysis_info::out)
+    is det.
 
-record_sharing_analysis_results(ModuleInfo, SharingAsTable, SCC,
+maybe_record_sharing_analysis_result(ModuleInfo, SharingAsTable, PredId,
         !AnalysisInfo) :-
-    list.foldl(record_sharing_analysis_result(ModuleInfo, SharingAsTable),
-        SCC, !AnalysisInfo).
+    module_info_pred_info(ModuleInfo, PredId, PredInfo),
+    ProcIds = pred_info_procids(PredInfo),
+    list.foldl(
+        maybe_record_sharing_analysis_result_2(ModuleInfo, SharingAsTable,
+            PredId, PredInfo),
+        ProcIds, !AnalysisInfo).
 
-:- pred record_sharing_analysis_result(module_info::in, sharing_as_table::in,
-    pred_proc_id::in, analysis_info::in, analysis_info::out) is det.
+:- pred maybe_record_sharing_analysis_result_2(module_info::in,
+    sharing_as_table::in, pred_id::in, pred_info::in, proc_id::in,
+    analysis_info::in, analysis_info::out) is det.
 
-record_sharing_analysis_result(ModuleInfo, SharingAsTable, PPId,
-        !AnalysisInfo) :-
-    PPId = proc(PredId, ProcId),
-    module_info_pred_proc_info(ModuleInfo, PredId, ProcId, PredInfo, ProcInfo),
+maybe_record_sharing_analysis_result_2(ModuleInfo, SharingAsTable, PredId,
+        PredInfo, ProcId, !AnalysisInfo) :-
     should_write_sharing_info(ModuleInfo, PredId, ProcId, PredInfo,
-        allow_type_spec_preds, ShouldWrite),
+        for_analysis_framework, ShouldWrite),
     (
         ShouldWrite = yes,
+        pred_info_proc_info(PredInfo, ProcId, ProcInfo),
+        PPId = proc(PredId, ProcId),
         (
             sharing_as_table_search(PPId, SharingAsTable,
                 sharing_as_and_status(SharingAsPrime, StatusPrime))
@@ -1130,7 +1134,15 @@ record_sharing_analysis_result(ModuleInf
             SharingAs = SharingAsPrime,
             Status0 = StatusPrime
         ;
-            unexpected(this_file, "record_sharing_analysis_result")
+            % Probably an exported `:- external' procedure.
+            bottom_sharing_is_safe_approximation(ModuleInfo, PredInfo,
+                ProcInfo)
+        ->
+            SharingAs = sharing_as_bottom,
+            Status0 = optimal
+        ;
+            SharingAs = sharing_as_top(set.init),
+            Status0 = optimal
         ),
         (
             SharingAs = sharing_as_bottom,
@@ -1199,31 +1211,13 @@ reason_implies_optimal(ModuleInfo, Analy
 
 handle_dep_procs(ModuleInfo, DepPPId, !AnalysisInfo) :-
     % Record that we depend on the result for the called procedure.
-    module_info_get_name(ModuleInfo, ThisModuleName),
     module_name_func_id(ModuleInfo, DepPPId, DepModuleName, DepFuncId),
     Call = structure_sharing_call,
-    record_dependency(ThisModuleName, analysis_name, DepModuleName, DepFuncId,
-        Call, !AnalysisInfo),
-
-    % If the called procedure didn't have an answer in the analysis registry,
-    % record the assumed answer (top) for it so that when it does get
-    % analysed, it will have something to compare against.
-    module_info_proc_info(ModuleInfo, DepPPId, ProcInfo),
-    FuncInfo = structure_sharing_func_info(ModuleInfo, ProcInfo),
-    lookup_matching_results(!.AnalysisInfo, DepModuleName, DepFuncId, FuncInfo,
-        Call, AnyResults : list(analysis_result(structure_sharing_call,
-            structure_sharing_answer))),
-    (
-        AnyResults = [],
-        Answer = top(FuncInfo, Call) : structure_sharing_answer,
-        record_result(DepModuleName, DepFuncId, Call, Answer, optimal,
-            !AnalysisInfo),
-        % Record a request as well.
-        record_request(analysis_name, DepModuleName, DepFuncId, Call,
-            !AnalysisInfo)
-    ;
-        AnyResults = [_ | _]
-    ).
+    Answer = _ : structure_sharing_answer,
+    get_func_info(ModuleInfo, DepModuleName, DepFuncId, Call, Answer,
+        FuncInfo),
+    record_dependency(DepModuleName, DepFuncId, FuncInfo, Call, Answer,
+        !AnalysisInfo).
 
 :- pred write_top_feedback(module_info::in, top_feedback::in, io::di, io::uo)
     is det.
@@ -1248,23 +1242,23 @@ write_top_feedback(ModuleInfo, Reason, !
 
 %-----------------------------------------------------------------------------%
 
-:- type allow_type_spec_preds
-    --->    allow_type_spec_preds
-    ;       disallow_type_spec_preds.
+:- type should_write_for
+    --->    for_analysis_framework
+    ;       for_pragma.
 
 :- pred should_write_sharing_info(module_info::in, pred_id::in, proc_id::in,
-    pred_info::in, allow_type_spec_preds::in, bool::out) is det.
+    pred_info::in, should_write_for::in, bool::out) is det.
 
-should_write_sharing_info(ModuleInfo, PredId, ProcId, PredInfo,
-        AllowTypeSpecPreds, ShouldWrite) :-
+should_write_sharing_info(ModuleInfo, PredId, ProcId, PredInfo, WhatFor,
+        ShouldWrite) :-
     (
         procedure_is_exported(ModuleInfo, PredInfo, ProcId),
         \+ is_unify_or_compare_pred(PredInfo),
 
         (
-            AllowTypeSpecPreds = allow_type_spec_preds
+            WhatFor = for_analysis_framework
         ;
-            AllowTypeSpecPreds = disallow_type_spec_preds,
+            WhatFor = for_pragma,
             % XXX These should be allowed, but the predicate declaration for
             % the specialized predicate is not produced before the structure
             % sharing pragmas are read in, resulting in an undefined predicate
Index: compiler/structure_sharing.domain.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/structure_sharing.domain.m,v
retrieving revision 1.34
diff -u -p -r1.34 structure_sharing.domain.m
--- compiler/structure_sharing.domain.m	28 May 2008 05:26:51 -0000	1.34
+++ compiler/structure_sharing.domain.m	3 Jun 2008 07:32:25 -0000
@@ -867,7 +867,7 @@ lookup_sharing_or_predict(ModuleInfo, Sh
     ;
         % or use top-sharing with appropriate message.
         SharingAs = top_sharing_not_found(PPId),
-        Status = suboptimal,
+        Status = optimal,
         IsPredicted = no
     ).
 
Index: compiler/tabling_analysis.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/tabling_analysis.m,v
retrieving revision 1.15
diff -u -p -r1.15 tabling_analysis.m
--- compiler/tabling_analysis.m	27 Mar 2008 02:29:43 -0000	1.15
+++ compiler/tabling_analysis.m	3 Jun 2008 07:32:26 -0000
@@ -137,6 +137,7 @@ analyse_mm_tabling_in_module(!ModuleInfo
         globals.io_lookup_bool_option(debug_mm_tabling_analysis, Debug, !IO),
         list.foldl(analyse_mm_tabling_in_scc(Debug, Pass1Only), SCCs,
             !ModuleInfo),
+
         % Only write mm_tabling_info pragmas to `.opt' files for
         % `--intermodule-optimisation' not `--intermodule-analysis'.
         (
@@ -146,6 +147,21 @@ analyse_mm_tabling_in_module(!ModuleInfo
             make_opt_int(!.ModuleInfo, !IO)
         ;
             true
+        ),
+
+        % Record results if making the analysis registry.  We do this in a
+        % separate pass so that we record results for exported `:- external'
+        % procedures, which don't get analysed because we don't have clauses
+        % for them.
+        (
+            MakeAnalysisReg = yes,
+            module_info_get_analysis_info(!.ModuleInfo, AnalysisInfo0),
+            module_info_predids(PredIds, !ModuleInfo),
+            list.foldl(maybe_record_mm_tabling_result(!.ModuleInfo),
+                PredIds, AnalysisInfo0, AnalysisInfo),
+            module_info_set_analysis_info(AnalysisInfo, !ModuleInfo)
+        ;
+            MakeAnalysisReg = no
         )
     ;
         UseMinimalModel = no
@@ -200,25 +216,6 @@ analyse_mm_tabling_in_scc(Debug, Pass1On
     ),
     list.foldl(Update, SCC, TablingInfo0, TablingInfo),
     module_info_set_mm_tabling_info(TablingInfo, !ModuleInfo),
-    %
-    % Record the analysis results for the intermodule analysis
-    %
-    module_info_get_globals(!.ModuleInfo, Globals),
-    globals.lookup_bool_option(Globals, make_analysis_registry,
-        MakeAnalysisRegistry),
-    (
-        MakeAnalysisRegistry = yes,
-        (
-            MaybeAnalysisStatus = yes(AnalysisStatus),
-            record_mm_tabling_analysis_results(TablingStatus, AnalysisStatus,
-                SCC, !ModuleInfo)
-        ;
-            MaybeAnalysisStatus = no,
-            unexpected(this_file, "process_scc: no analysis status")
-        )
-    ;
-        MakeAnalysisRegistry = no
-    ),
     (
         Pass1Only = no,
         list.foldl(annotate_proc, SCC, !ModuleInfo)
@@ -450,12 +447,13 @@ check_call_for_mm_tabling(CalleePPId, Ca
         globals.lookup_bool_option(Globals, intermodule_analysis, Intermod),
         (
             Intermod = yes,
-            pred_info_is_imported(CalleePredInfo)
+            pred_info_is_imported_not_external(CalleePredInfo),
+            not is_unify_or_compare_pred(CalleePredInfo)
         ->
             % Use the intermodule analysis framework if this is an imported
             % procedure and `--intermodule-analysis' is enabled.
             %
-            search_analysis_status(CalleePPId, Result0, AnalysisStatus, SCC,
+            search_analysis_status(CalleePPId, Result0, AnalysisStatus,
                 !ModuleInfo),
             (
                 Result0 = mm_tabled_conditional,
@@ -484,7 +482,7 @@ check_call_for_mm_tabling(CalleePPId, Ca
                 Result = mm_tabled_may_call,
                 (
                     Intermod = yes,
-                    MaybeAnalysisStatus = yes(suboptimal)
+                    MaybeAnalysisStatus = yes(optimal)
                 ;
                     Intermod = no,
                     MaybeAnalysisStatus = no
@@ -739,14 +737,9 @@ annotate_call(CalleePPId, CallArgs, VarT
             IntermodAnalysis),
         (
             IntermodAnalysis = yes,
-            pred_info_is_imported(CalleePredInfo)
+            pred_info_is_imported_not_external(CalleePredInfo)
         ->
-            % NOTE: we set the value of SCC to a dummy value here.
-            % This is okay because it only needs a meaningful value when
-            % building the analysis files; it won't be used when compiling to
-            % target code.
-            SCC = [],
-            search_analysis_status(CalleePPId, Result, AnalysisStatus, SCC,
+            search_analysis_status(CalleePPId, Result, AnalysisStatus,
                 !ModuleInfo),
             (
                 AnalysisStatus = invalid,
@@ -818,52 +811,67 @@ make_opt_int(ModuleInfo, !IO) :-
 
 write_pragma_mm_tabling_info(ModuleInfo, TablingInfo, PredId, !IO) :-
     module_info_pred_info(ModuleInfo, PredId, PredInfo),
-    should_write_mm_tabling_info(ModuleInfo, PredId, PredInfo, ShouldWrite),
+    ProcIds = pred_info_procids(PredInfo),
+    list.foldl(
+        write_pragma_mm_tabling_info_2(ModuleInfo, TablingInfo, PredId,
+            PredInfo), 
+        ProcIds, !IO).
+
+:- pred write_pragma_mm_tabling_info_2(module_info::in, mm_tabling_info::in,
+    pred_id::in, pred_info::in, proc_id::in, io::di, io::uo) is det.
+
+write_pragma_mm_tabling_info_2(ModuleInfo, TablingInfo, PredId, PredInfo,
+        ProcId, !IO) :-
+    should_write_mm_tabling_info(ModuleInfo, PredId, ProcId, PredInfo,
+        for_pragma, ShouldWrite),
     (
         ShouldWrite  = yes,
         ModuleName   = pred_info_module(PredInfo),
         Name         = pred_info_name(PredInfo),
         Arity        = pred_info_orig_arity(PredInfo),
         PredOrFunc   = pred_info_is_pred_or_func(PredInfo),
-        ProcIds      = pred_info_procids(PredInfo),
-        OutputPragma = (pred(ProcId::in, !.IO::di, !:IO::uo) is det :-
-            proc_id_to_int(ProcId, ModeNum),
-            (
-                map.search(TablingInfo, proc(PredId, ProcId), ProcTablingInfo),
-                ProcTablingInfo = proc_mm_tabling_info(Status, _)
-            ->
-                mercury_output_pragma_mm_tabling_info(PredOrFunc,
-                    qualified(ModuleName, Name), Arity, ModeNum, Status, !IO)
-            ;
-                true
-            )
-        ),
-        list.foldl(OutputPragma, ProcIds, !IO)
+        proc_id_to_int(ProcId, ModeNum),
+        (
+            map.search(TablingInfo, proc(PredId, ProcId), ProcTablingInfo),
+            ProcTablingInfo = proc_mm_tabling_info(Status, _)
+        ->
+            mercury_output_pragma_mm_tabling_info(PredOrFunc,
+                qualified(ModuleName, Name), Arity, ModeNum, Status, !IO)
+        ;
+            true
+        )
     ;
         ShouldWrite = no
     ).
 
-:- pred should_write_mm_tabling_info(module_info::in, pred_id::in,
-    pred_info::in, bool::out) is det.
+:- type should_write_for
+    --->    for_analysis_framework
+    ;       for_pragma.
 
-should_write_mm_tabling_info(ModuleInfo, PredId, PredInfo, ShouldWrite) :-
-    pred_info_get_import_status(PredInfo, ImportStatus),
+:- pred should_write_mm_tabling_info(module_info::in, pred_id::in, proc_id::in,
+    pred_info::in, should_write_for::in, bool::out) is det.
+
+should_write_mm_tabling_info(ModuleInfo, PredId, ProcId, PredInfo, WhatFor,
+        ShouldWrite) :-
     (
-        ( ImportStatus = status_exported
-        ; ImportStatus = status_opt_exported
-        ),
+        procedure_is_exported(ModuleInfo, PredInfo, ProcId),
         not is_unify_or_compare_pred(PredInfo),
-        module_info_get_type_spec_info(ModuleInfo, TypeSpecInfo),
-        TypeSpecInfo = type_spec_info(_, TypeSpecForcePreds, _, _),
-        not set.member(PredId, TypeSpecForcePreds),
-        %
-        % XXX Writing out pragmas for the automatically generated class
-        % instance methods causes the compiler to abort when it reads them
-        % back in.
-        %
-        pred_info_get_markers(PredInfo, Markers),
-        not check_marker(Markers, marker_class_instance_method),
-        not check_marker(Markers, marker_named_class_instance_method)
+        (
+            WhatFor = for_analysis_framework
+        ;
+            WhatFor = for_pragma,
+            module_info_get_type_spec_info(ModuleInfo, TypeSpecInfo),
+            TypeSpecInfo = type_spec_info(_, TypeSpecForcePreds, _, _),
+            not set.member(PredId, TypeSpecForcePreds),
+            %
+            % XXX Writing out pragmas for the automatically generated class
+            % instance methods causes the compiler to abort when it reads them
+            % back in.
+            %
+            pred_info_get_markers(PredInfo, Markers),
+            not check_marker(Markers, marker_class_instance_method),
+            not check_marker(Markers, marker_named_class_instance_method)
+        )
     ->
         ShouldWrite = yes
     ;
@@ -942,40 +950,31 @@ mm_tabling_status_to_string(mm_tabled_wi
 mm_tabling_status_to_string(mm_tabled_conditional,
     "mm_tabled_conditional").
 
-:- pred search_analysis_status(pred_proc_id::in,
-    mm_tabling_status::out, analysis_status::out, scc::in,
-    module_info::in, module_info::out) is det.
+:- pred search_analysis_status(pred_proc_id::in, mm_tabling_status::out,
+    analysis_status::out, module_info::in, module_info::out) is det.
 
-search_analysis_status(PPId, Result, AnalysisStatus, CallerSCC,
-        !ModuleInfo) :-
+search_analysis_status(PPId, Result, AnalysisStatus, !ModuleInfo) :-
     module_info_get_analysis_info(!.ModuleInfo, AnalysisInfo0),
     search_analysis_status_2(!.ModuleInfo, PPId, Result, AnalysisStatus,
-        CallerSCC, AnalysisInfo0, AnalysisInfo),
+        AnalysisInfo0, AnalysisInfo),
     module_info_set_analysis_info(AnalysisInfo, !ModuleInfo).
 
 :- pred search_analysis_status_2(module_info::in, pred_proc_id::in,
-    mm_tabling_status::out, analysis_status::out, scc::in,
+    mm_tabling_status::out, analysis_status::out,
     analysis_info::in, analysis_info::out) is det.
 
-search_analysis_status_2(ModuleInfo, PPId, Result, AnalysisStatus, CallerSCC,
+search_analysis_status_2(ModuleInfo, PPId, Result, AnalysisStatus,
         !AnalysisInfo) :-
     mmc_analysis.module_name_func_id(ModuleInfo, PPId, ModuleName, FuncId),
     Call = any_call,
-    analysis.lookup_best_result(!.AnalysisInfo, ModuleName, FuncId,
-        no_func_info, Call, MaybeBestStatus),
-    module_info_get_globals(ModuleInfo, Globals),
-    globals.lookup_bool_option(Globals, make_analysis_registry,
-        MakeAnalysisRegistry),
-    (
-        MaybeBestStatus = yes(analysis_result(BestCall,
-            mm_tabling_analysis_answer(Result), AnalysisStatus)),
-        (
-            MakeAnalysisRegistry = yes,
-            record_dependencies(ModuleName, FuncId, BestCall,
-                ModuleInfo, CallerSCC, !AnalysisInfo)
-        ;
-            MakeAnalysisRegistry = no
-        )
+    lookup_best_result(!.AnalysisInfo, ModuleName, FuncId, no_func_info, Call,
+        MaybeBestStatus),
+    (
+        MaybeBestStatus = yes(analysis_result(BestCall, BestAnswer,
+            AnalysisStatus)),
+        BestAnswer = mm_tabling_analysis_answer(Result), 
+        record_dependency(ModuleName, FuncId, no_func_info, BestCall,
+            _ : mm_tabling_analysis_answer, !AnalysisInfo)
     ;
         MaybeBestStatus = no,
         % If we do not have any information about the callee procedure
@@ -983,73 +982,57 @@ search_analysis_status_2(ModuleInfo, PPI
         % procedure.
         top(no_func_info, Call) = Answer,
         Answer = mm_tabling_analysis_answer(Result),
-        module_is_local(!.AnalysisInfo, ModuleName, IsLocal),
-        (
-            IsLocal = yes,
-            AnalysisStatus = suboptimal,
-            (
-                MakeAnalysisRegistry = yes,
-                analysis.record_result(ModuleName, FuncId, Call, Answer,
-                    AnalysisStatus, !AnalysisInfo),
-                analysis.record_request(analysis_name, ModuleName, FuncId,
-                    Call, !AnalysisInfo),
-                record_dependencies(ModuleName, FuncId, Call,
-                    ModuleInfo, CallerSCC, !AnalysisInfo)
-            ;
-                MakeAnalysisRegistry = no
-            )
-        ;
-            IsLocal = no,
-            % We can't do any better anyway.
-            AnalysisStatus = optimal
-        )
+        AnalysisStatus = optimal,
+        record_request(analysis_name, ModuleName, FuncId, Call, !AnalysisInfo)
     ).
 
-    % XXX if the procedures in CallerSCC definitely come from the
-    % same module then we don't need to record the dependency so many
-    % times, at least while we only have module-level granularity.
-    %
-:- pred record_dependencies(module_name::in, func_id::in, Call::in,
-    module_info::in, scc::in, analysis_info::in, analysis_info::out)
-    is det <= call_pattern(FuncInfo, Call).
-
-record_dependencies(ModuleName, FuncId, Call, ModuleInfo, CallerSCC,
-        !AnalysisInfo) :-
-    RecordDependency = (pred(CallerPPId::in, Info0::in, Info::out) is det :-
-        module_name_func_id(ModuleInfo, CallerPPId, CallerModuleName, _),
-        record_dependency(CallerModuleName, analysis_name, ModuleName, FuncId,
-            Call, Info0, Info)
-    ),
-    list.foldl(RecordDependency, CallerSCC, !AnalysisInfo).
-
-:- pred record_mm_tabling_analysis_results(mm_tabling_status::in,
-    analysis_status::in, scc::in, module_info::in, module_info::out) is det.
-
-record_mm_tabling_analysis_results(Status, ResultStatus, SCC, !ModuleInfo) :-
-    module_info_get_analysis_info(!.ModuleInfo, AnalysisInfo0),
-    list.foldl(
-        record_mm_tabling_analysis_result(!.ModuleInfo, Status, ResultStatus),
-        SCC, AnalysisInfo0, AnalysisInfo),
-    module_info_set_analysis_info(AnalysisInfo, !ModuleInfo).
-
-:- pred record_mm_tabling_analysis_result(module_info::in,
-    mm_tabling_status::in, analysis_status::in, pred_proc_id::in,
+:- pred maybe_record_mm_tabling_result(module_info::in, pred_id::in,
     analysis_info::in, analysis_info::out) is det.
 
-record_mm_tabling_analysis_result(ModuleInfo, Status, ResultStatus,
-        PPId @ proc(PredId, _ProcId), !AnalysisInfo) :-
+maybe_record_mm_tabling_result(ModuleInfo, PredId, !AnalysisInfo) :-
     module_info_pred_info(ModuleInfo, PredId, PredInfo),
-    should_write_mm_tabling_info(ModuleInfo, PredId, PredInfo, ShouldWrite),
+    ProcIds = pred_info_procids(PredInfo),
+    list.foldl(maybe_record_mm_tabling_result_2(ModuleInfo, PredId, PredInfo),
+        ProcIds, !AnalysisInfo).
+
+:- pred maybe_record_mm_tabling_result_2(module_info::in, pred_id::in,
+    pred_info::in, proc_id::in, analysis_info::in, analysis_info::out) is det.
+
+maybe_record_mm_tabling_result_2(ModuleInfo, PredId, PredInfo, ProcId,
+        !AnalysisInfo) :-
+    should_write_mm_tabling_info(ModuleInfo, PredId, ProcId, PredInfo,
+        for_analysis_framework, ShouldWrite),
     (
         ShouldWrite = yes,
-        mmc_analysis.module_name_func_id(ModuleInfo, PPId, ModuleName, FuncId),
-        Answer = mm_tabling_analysis_answer(Status),
-        record_result(ModuleName, FuncId, any_call, Answer, ResultStatus,
-            !AnalysisInfo)
+        PPId = proc(PredId, ProcId),
+        module_info_get_mm_tabling_info(ModuleInfo, TablingInfo),
+        lookup_proc_mm_tabling_info(TablingInfo, PPId, Status, ResultStatus),
+        module_name_func_id(ModuleInfo, PPId, ModuleName, FuncId),
+        record_result(ModuleName, FuncId, any_call,
+            mm_tabling_analysis_answer(Status), ResultStatus, !AnalysisInfo)
     ;
         ShouldWrite = no
     ).
 
+:- pred lookup_proc_mm_tabling_info(mm_tabling_info::in, pred_proc_id::in,
+    mm_tabling_status::out, analysis_status::out) is det.
+
+lookup_proc_mm_tabling_info(TablingInfo, PPId, Status, ResultStatus) :-
+    ( map.search(TablingInfo, PPId, ProcTablingInfo) ->
+        ProcTablingInfo = proc_mm_tabling_info(Status, MaybeResultStatus),
+        (
+            MaybeResultStatus = yes(ResultStatus)
+        ;
+            MaybeResultStatus = no,
+            unexpected(this_file,
+                "lookup_proc_mm_tabling_info: no result status")
+        )
+    ;
+        % Probably an exported `:- external' procedure.
+        Status = mm_tabled_may_call,
+        ResultStatus = optimal
+    ).
+
 %----------------------------------------------------------------------------%
 %
 % Code for printing out debugging traces
Index: compiler/trailing_analysis.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/trailing_analysis.m,v
retrieving revision 1.34
diff -u -p -r1.34 trailing_analysis.m
--- compiler/trailing_analysis.m	27 Mar 2008 02:29:43 -0000	1.34
+++ compiler/trailing_analysis.m	3 Jun 2008 07:32:26 -0000
@@ -146,6 +146,7 @@ analyse_trail_usage(!ModuleInfo, !IO) :-
         hlds_dependency_info_get_dependency_ordering(DepInfo, SCCs),
         globals.io_lookup_bool_option(debug_trail_usage, Debug, !IO),
         list.foldl(process_scc(Debug, Pass1Only), SCCs, !ModuleInfo),
+
         % Only write trailing analysis pragmas to `.opt' files for
         % `--intermodule-optimization', not `--intermodule-analysis'.
         (
@@ -155,6 +156,21 @@ analyse_trail_usage(!ModuleInfo, !IO) :-
             make_opt_int(!.ModuleInfo, !IO)
         ;
             true
+        ),
+
+        % Record results if making the analysis registry.  We do this in a
+        % separate pass so that we record results for exported `:- external'
+        % procedures, which don't get analysed because we don't have clauses
+        % for them.
+        (
+            MakeAnalysisReg = yes,
+            module_info_get_analysis_info(!.ModuleInfo, AnalysisInfo0),
+            module_info_predids(PredIds, !ModuleInfo),
+            list.foldl(maybe_record_trailing_result(!.ModuleInfo),
+                PredIds, AnalysisInfo0, AnalysisInfo),
+            module_info_set_analysis_info(AnalysisInfo, !ModuleInfo)
+        ;
+            MakeAnalysisReg = no
         )
     ;
         UseTrail = no
@@ -205,23 +221,6 @@ process_scc(Debug, Pass1Only, SCC, !Modu
     list.foldl(Update, SCC, TrailingInfo0, TrailingInfo),
     module_info_set_trailing_info(TrailingInfo, !ModuleInfo),
 
-    % Record the analysis results for the intermodule analysis.
-    module_info_get_globals(!.ModuleInfo, Globals),
-    globals.lookup_bool_option(Globals, make_analysis_registry,
-        MakeAnalysisRegistry),
-    (
-        MakeAnalysisRegistry = yes,
-        (
-            MaybeAnalysisStatus = yes(AnalysisStatus),
-            record_trailing_analysis_results(TrailingStatus, AnalysisStatus,
-                SCC, !ModuleInfo)
-        ;
-            MaybeAnalysisStatus = no,
-            unexpected(this_file, "process_scc: no analysis status")
-        )
-    ;
-        MakeAnalysisRegistry = no
-    ),
     (
         Pass1Only = no,
         list.foldl(annotate_proc, SCC, !ModuleInfo)
@@ -383,12 +382,12 @@ check_goal_for_trail_mods(SCC, VarTypes,
                 Intermod),
             (
                 Intermod = yes,
-                pred_info_is_imported(CallPredInfo)
+                pred_info_is_imported_not_external(CallPredInfo)
             ->
                 % With --intermodule-analysis use check_call_2 to look up
                 % results for locally defined procedures, otherwise we use
                 % the intermodule analysis framework.
-                search_analysis_status(CallPPId, Result0, AnalysisStatus, SCC,
+                search_analysis_status(CallPPId, Result0, AnalysisStatus,
                     !ModuleInfo),
                 (
                     Result0 = trail_conditional,
@@ -413,7 +412,7 @@ check_goal_for_trail_mods(SCC, VarTypes,
                     Result = trail_may_modify,
                     (
                         Intermod = yes,
-                        MaybeAnalysisStatus = yes(suboptimal)
+                        MaybeAnalysisStatus = yes(optimal)
                     ;
                         Intermod = no,
                         MaybeAnalysisStatus = no
@@ -900,12 +899,7 @@ annotate_goal_2(VarTypes, GoalInfo, !Goa
                 IntermodAnalysis = yes,
                 pred_info_is_imported(CallPredInfo)
             ->
-                % NOTE: we set the value of SCC to a dummy value here.
-                % This is OK because it only needs a meaningful value
-                % when building the analysis files; it won't be used
-                % when compiling to target code.
-                SCC = [],
-                search_analysis_status(CallPPId, Result, AnalysisStatus, SCC,
+                search_analysis_status(CallPPId, Result, AnalysisStatus,
                     !ModuleInfo),
 
                 % XXX We shouldn't be getting invalid analysis results at this
@@ -1061,50 +1055,67 @@ make_opt_int(ModuleInfo, !IO) :-
 
 write_pragma_trailing_info(ModuleInfo, TrailingInfo, PredId, !IO) :-
     module_info_pred_info(ModuleInfo, PredId, PredInfo),
-    should_write_trailing_info(ModuleInfo, PredId, PredInfo, ShouldWrite),
+    ProcIds = pred_info_procids(PredInfo),
+    list.foldl(
+        write_pragma_trailing_info_2(ModuleInfo, TrailingInfo, PredId,
+            PredInfo), 
+        ProcIds, !IO).
+
+:- pred write_pragma_trailing_info_2(module_info::in, trailing_info::in,
+    pred_id::in, pred_info::in, proc_id::in, io::di, io::uo) is det.
+
+write_pragma_trailing_info_2(ModuleInfo, TrailingInfo, PredId, PredInfo,
+        ProcId, !IO) :-
+    should_write_trailing_info(ModuleInfo, PredId, ProcId, PredInfo,
+        for_pragma, ShouldWrite),
     (
         ShouldWrite = yes,
         ModuleName = pred_info_module(PredInfo),
         Name       = pred_info_name(PredInfo),
         Arity      = pred_info_orig_arity(PredInfo),
         PredOrFunc = pred_info_is_pred_or_func(PredInfo),
-        ProcIds    = pred_info_procids(PredInfo),
-        list.foldl((pred(ProcId::in, !.IO::di, !:IO::uo) is det :-
-            proc_id_to_int(ProcId, ModeNum),
-            (
-                map.search(TrailingInfo, proc(PredId, ProcId), ProcTrailInfo),
-                ProcTrailInfo = proc_trailing_info(Status, _)
-            ->
-                mercury_output_pragma_trailing_info(PredOrFunc,
-                    qualified(ModuleName, Name), Arity, ModeNum, Status, !IO)
-            ;
-                true
-            )), ProcIds, !IO)
+        proc_id_to_int(ProcId, ModeNum),
+        (
+            map.search(TrailingInfo, proc(PredId, ProcId), ProcTrailInfo),
+            ProcTrailInfo = proc_trailing_info(Status, _)
+        ->
+            mercury_output_pragma_trailing_info(PredOrFunc,
+                qualified(ModuleName, Name), Arity, ModeNum, Status, !IO)
+        ;
+            true
+        )
     ;
         ShouldWrite = no
     ).
 
-:- pred should_write_trailing_info(module_info::in, pred_id::in,
-    pred_info::in, bool::out) is det.
+:- type should_write_for
+    --->    for_analysis_framework
+    ;       for_pragma.
 
-should_write_trailing_info(ModuleInfo, PredId, PredInfo, ShouldWrite) :-
-    pred_info_get_import_status(PredInfo, ImportStatus),
+:- pred should_write_trailing_info(module_info::in, pred_id::in, proc_id::in,
+    pred_info::in, should_write_for::in, bool::out) is det.
+
+should_write_trailing_info(ModuleInfo, PredId, ProcId, PredInfo, WhatFor,
+        ShouldWrite) :-
     (
-        ( ImportStatus = status_exported
-        ; ImportStatus = status_opt_exported
-        ),
+        procedure_is_exported(ModuleInfo, PredInfo, ProcId),
         not is_unify_or_compare_pred(PredInfo),
-        module_info_get_type_spec_info(ModuleInfo, TypeSpecInfo),
-        TypeSpecInfo = type_spec_info(_, TypeSpecForcePreds, _, _),
-        not set.member(PredId, TypeSpecForcePreds),
-        %
-        % XXX Writing out pragmas for the automatically generated class
-        % instance methods causes the compiler to abort when it reads them
-        % back in.
-        %
-        pred_info_get_markers(PredInfo, Markers),
-        not check_marker(Markers, marker_class_instance_method),
-        not check_marker(Markers, marker_named_class_instance_method)
+        (
+            WhatFor = for_analysis_framework
+        ;
+            WhatFor = for_pragma,
+            module_info_get_type_spec_info(ModuleInfo, TypeSpecInfo),
+            TypeSpecInfo = type_spec_info(_, TypeSpecForcePreds, _, _),
+            not set.member(PredId, TypeSpecForcePreds),
+            %
+            % XXX Writing out pragmas for the automatically generated class
+            % instance methods causes the compiler to abort when it reads them
+            % back in.
+            %
+            pred_info_get_markers(PredInfo, Markers),
+            not check_marker(Markers, marker_class_instance_method),
+            not check_marker(Markers, marker_named_class_instance_method)
+        )
     ->
         ShouldWrite = yes
     ;
@@ -1173,122 +1184,86 @@ trailing_status_to_string(trail_may_modi
 trailing_status_to_string(trail_will_not_modify, "will_not_modify_trail").
 trailing_status_to_string(trail_conditional, "conditional").
 
-:- pred search_analysis_status(pred_proc_id::in,
-    trailing_status::out, analysis_status::out, scc::in,
-    module_info::in, module_info::out) is det.
+:- pred search_analysis_status(pred_proc_id::in, trailing_status::out,
+    analysis_status::out, module_info::in, module_info::out) is det.
 
-search_analysis_status(PPId, Result, AnalysisStatus, CallerSCC,
-        !ModuleInfo) :-
+search_analysis_status(PPId, Result, AnalysisStatus, !ModuleInfo) :-
     module_info_get_analysis_info(!.ModuleInfo, AnalysisInfo0),
     search_analysis_status_2(!.ModuleInfo, PPId, Result, AnalysisStatus,
-        CallerSCC, AnalysisInfo0, AnalysisInfo),
+        AnalysisInfo0, AnalysisInfo),
     module_info_set_analysis_info(AnalysisInfo, !ModuleInfo).
 
 :- pred search_analysis_status_2(module_info::in, pred_proc_id::in,
-    trailing_status::out, analysis_status::out, scc::in,
+    trailing_status::out, analysis_status::out,
     analysis_info::in, analysis_info::out) is det.
 
-search_analysis_status_2(ModuleInfo, PPId, Result, AnalysisStatus, CallerSCC,
+search_analysis_status_2(ModuleInfo, PPId, Result, AnalysisStatus,
         !AnalysisInfo) :-
     mmc_analysis.module_name_func_id(ModuleInfo, PPId, ModuleName, FuncId),
     Call = any_call,
     analysis.lookup_best_result(!.AnalysisInfo, ModuleName, FuncId,
         no_func_info, Call, MaybeBestStatus),
-    module_info_get_globals(ModuleInfo, Globals),
-    globals.lookup_bool_option(Globals, make_analysis_registry,
-        MakeAnalysisRegistry),
     (
         MaybeBestStatus = yes(analysis_result(BestCall,
             trailing_analysis_answer(Result), AnalysisStatus)),
-        (
-            MakeAnalysisRegistry = yes,
-            record_dependencies(ModuleName, FuncId, BestCall,
-                ModuleInfo, CallerSCC, !AnalysisInfo)
-        ;
-            MakeAnalysisRegistry = no
-        )
+        record_dependency(ModuleName, FuncId, no_func_info, BestCall,
+            _ : trailing_analysis_answer, !AnalysisInfo)
     ;
         MaybeBestStatus = no,
         % If we do not have any information about the callee procedure
         % then assume that it modifies the trail.
         top(no_func_info, Call) = Answer,
         Answer = trailing_analysis_answer(Result),
-        module_is_local(!.AnalysisInfo, ModuleName, IsLocal),
-        (
-            IsLocal = yes,
-            AnalysisStatus = suboptimal,
-            (
-                MakeAnalysisRegistry = yes,
-                PPId = proc(PredId, _),
-                module_info_pred_info(ModuleInfo, PredId, PredInfo),
-                should_write_trailing_info(ModuleInfo, PredId, PredInfo,
-                    ShouldWrite),
-                (
-                    ShouldWrite = yes,
-                    analysis.record_result(ModuleName, FuncId,
-                        Call, Answer, AnalysisStatus, !AnalysisInfo),
-                    analysis.record_request(analysis_name, ModuleName, FuncId,
-                        Call, !AnalysisInfo),
-                    record_dependencies(ModuleName, FuncId, Call,
-                        ModuleInfo, CallerSCC, !AnalysisInfo)
-                ;
-                    ShouldWrite = no
-                )
-            ;
-                MakeAnalysisRegistry = no
-            )
-        ;
-            IsLocal = no,
-            % We can't do any better anyway.
-            AnalysisStatus = optimal
-        )
+        AnalysisStatus = optimal,
+        record_request(analysis_name, ModuleName, FuncId, Call, !AnalysisInfo)
     ).
 
-    % XXX if the procedures in CallerSCC definitely come from the
-    % same module then we don't need to record the dependency so many
-    % times, at least while we only have module-level granularity.
-    %
-:- pred record_dependencies(module_name::in, func_id::in, Call::in,
-    module_info::in, scc::in, analysis_info::in, analysis_info::out)
-    is det <= call_pattern(FuncInfo, Call).
-
-record_dependencies(ModuleName, FuncId, Call, ModuleInfo, CallerSCC,
-        !AnalysisInfo) :-
-    list.foldl((pred(CallerPPId::in, Info0::in, Info::out) is det :-
-        mmc_analysis.module_name_func_id(ModuleInfo, CallerPPId,
-            CallerModuleName, _),
-        analysis.record_dependency(CallerModuleName, analysis_name,
-            ModuleName, FuncId, Call, Info0, Info)
-    ), CallerSCC, !AnalysisInfo).
-
-:- pred record_trailing_analysis_results(trailing_status::in,
-    analysis_status::in, scc::in,
-    module_info::in, module_info::out) is det.
-
-record_trailing_analysis_results(Status, ResultStatus, SCC, !ModuleInfo) :-
-    module_info_get_analysis_info(!.ModuleInfo, AnalysisInfo0),
-    list.foldl(
-        record_trailing_analysis_result(!.ModuleInfo, Status, ResultStatus),
-        SCC, AnalysisInfo0, AnalysisInfo),
-    module_info_set_analysis_info(AnalysisInfo, !ModuleInfo).
-
-:- pred record_trailing_analysis_result(module_info::in, trailing_status::in,
-    analysis_status::in, pred_proc_id::in,
+:- pred maybe_record_trailing_result(module_info::in, pred_id::in,
     analysis_info::in, analysis_info::out) is det.
 
-record_trailing_analysis_result(ModuleInfo, Status, ResultStatus,
-        PPId @ proc(PredId, _ProcId), AnalysisInfo0, AnalysisInfo) :-
+maybe_record_trailing_result(ModuleInfo, PredId, !AnalysisInfo) :-
     module_info_pred_info(ModuleInfo, PredId, PredInfo),
-    should_write_trailing_info(ModuleInfo, PredId, PredInfo, ShouldWrite),
+    ProcIds = pred_info_procids(PredInfo),
+    list.foldl(maybe_record_trailing_result_2(ModuleInfo, PredId, PredInfo),
+        ProcIds, !AnalysisInfo).
+
+:- pred maybe_record_trailing_result_2(module_info::in, pred_id::in,
+    pred_info::in, proc_id::in, analysis_info::in, analysis_info::out) is det.
+
+maybe_record_trailing_result_2(ModuleInfo, PredId, PredInfo, ProcId,
+        !AnalysisInfo) :-
+    should_write_trailing_info(ModuleInfo, PredId, ProcId, PredInfo,
+        for_analysis_framework, ShouldWrite),
     (
         ShouldWrite = yes,
-        mmc_analysis.module_name_func_id(ModuleInfo, PPId, ModuleName, FuncId),
-        analysis.record_result(ModuleName, FuncId, any_call,
-            trailing_analysis_answer(Status), ResultStatus,
-            AnalysisInfo0, AnalysisInfo)
+        PPId = proc(PredId, ProcId),
+        module_info_get_trailing_info(ModuleInfo, TrailingInfo),
+        lookup_proc_trailing_info(TrailingInfo, PPId, Status, ResultStatus),
+        module_name_func_id(ModuleInfo, PPId, ModuleName, FuncId),
+        record_result(ModuleName, FuncId, any_call,
+            trailing_analysis_answer(Status), ResultStatus, !AnalysisInfo)
+    ;
+        ShouldWrite = no
+    ).
+
+:- pred lookup_proc_trailing_info(trailing_info::in, pred_proc_id::in,
+    trailing_status::out, analysis_status::out) is det.
+
+lookup_proc_trailing_info(TrailingInfo, PPId, Status, ResultStatus) :-
+    ( map.search(TrailingInfo, PPId, ProcTrailingInfo) ->
+        ProcTrailingInfo = proc_trailing_info(Status, MaybeResultStatus),
+        (
+            MaybeResultStatus = yes(ResultStatus)
+        ;
+            MaybeResultStatus = no,
+            unexpected(this_file,
+                "lookup_proc_trailing_info: no result status")
+        )
     ;
-        ShouldWrite = no,
-        AnalysisInfo = AnalysisInfo0
+        % Probably an exported `:- external' procedure wouldn't have been
+        % analysed.
+        Status = trail_may_modify,
+        ResultStatus = optimal
     ).
 
 %----------------------------------------------------------------------------%
Index: compiler/unused_args.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/unused_args.m,v
retrieving revision 1.153
diff -u -p -r1.153 unused_args.m
--- compiler/unused_args.m	27 Mar 2008 02:29:43 -0000	1.153
+++ compiler/unused_args.m	3 Jun 2008 07:32:27 -0000
@@ -287,8 +287,12 @@ process_module(!ModuleInfo, !Specs, !IO)
     (
         MakeAnalysisRegistry = yes,
         module_info_get_analysis_info(!.ModuleInfo, AnalysisInfo0),
+        module_info_predids(PredIds, !ModuleInfo),
+        list.foldl(
+            maybe_record_intermod_unused_args(!.ModuleInfo, UnusedArgInfo),
+            PredIds, AnalysisInfo0, AnalysisInfo1),
         list.foldl(record_intermod_dependencies(!.ModuleInfo),
-            PredProcs, AnalysisInfo0, AnalysisInfo),
+            PredProcs, AnalysisInfo1, AnalysisInfo),
         module_info_set_analysis_info(AnalysisInfo, !ModuleInfo)
     ;
         MakeAnalysisRegistry = no
@@ -411,17 +415,16 @@ setup_proc_args(PredId, ProcId, !VarUsag
             % (opt_imported preds) since we may be able to do better with the
             % information in this module.
             Intermod = yes,
-            pred_info_is_imported(PredInfo)
+            pred_info_is_imported_not_external(PredInfo),
+            not is_unify_or_compare_pred(PredInfo)
         ->
             PredModule = pred_info_module(PredInfo),
-            PredOrFunc = pred_info_is_pred_or_func(PredInfo),
-            PredName = pred_info_name(PredInfo),
             PredArity = pred_info_orig_arity(PredInfo),
-            FuncId = pred_or_func_name_arity_to_func_id(PredOrFunc,
-                PredName, PredArity, ProcId),
             FuncInfo = unused_args_func_info(PredArity),
             module_info_get_analysis_info(!.ModuleInfo, AnalysisInfo0),
-            lookup_best_result(AnalysisInfo0, PredModule, FuncId,
+            module_name_func_id_from_pred_info(PredInfo, ProcId, ModuleId,
+                FuncId),
+            lookup_best_result(AnalysisInfo0, ModuleId, FuncId,
                 FuncInfo, unused_args_call, MaybeBestResult),
             (
                 MaybeBestResult = yes(analysis_result(_, BestAnswer, _)),
@@ -449,34 +452,8 @@ setup_proc_args(PredId, ProcId, !VarUsag
                 AnalysisInfo = AnalysisInfo0
             ;
                 MaybeBestResult = no,
-                module_is_local(AnalysisInfo0, PredModule, IsLocal),
-                (
-                    IsLocal = yes,
-                    % XXX makes too many requests
-                    globals.lookup_bool_option(Globals,
-                        make_analysis_registry, MakeAnalysisRegistry),
-                    (
-                        MakeAnalysisRegistry = yes,
-                        ( is_unify_or_compare_pred(PredInfo) ->
-                            AnalysisInfo = AnalysisInfo0
-                        ;
-                            Answer = top(FuncInfo, unused_args_call)
-                                : unused_args_answer,
-                            analysis.record_result(PredModule, FuncId,
-                                unused_args_call, Answer, suboptimal,
-                                AnalysisInfo0, AnalysisInfo1),
-                            analysis.record_request(analysis_name,
-                                PredModule, FuncId, unused_args_call,
-                                AnalysisInfo1, AnalysisInfo)
-                        )
-                    ;
-                        MakeAnalysisRegistry = no,
-                        AnalysisInfo = AnalysisInfo0
-                    )
-                ;
-                    IsLocal = no,
-                    AnalysisInfo = AnalysisInfo0
-                )
+                record_request(analysis_name, PredModule, FuncId,
+                    unused_args_call, AnalysisInfo0, AnalysisInfo)
             ),
             module_info_set_analysis_info(AnalysisInfo, !ModuleInfo)
         ;
@@ -1003,53 +980,32 @@ create_new_pred(UnusedArgInfo, proc(Pred
     module_info_pred_proc_info(!.ModuleInfo, PredId, ProcId,
         OrigPredInfo, OrigProcInfo),
     PredModule = pred_info_module(OrigPredInfo),
-    PredName = pred_info_name(OrigPredInfo),
 
     module_info_get_globals(!.ModuleInfo, Globals),
     globals.lookup_bool_option(Globals, intermodule_analysis, Intermod),
     (
         Intermod = yes,
         module_info_get_analysis_info(!.ModuleInfo, AnalysisInfo0),
-        PredOrFunc = pred_info_is_pred_or_func(OrigPredInfo),
-        PredArity = pred_info_orig_arity(OrigPredInfo),
-        FuncId = pred_or_func_name_arity_to_func_id(PredOrFunc,
-            PredName, PredArity, ProcId),
-        FuncInfo = unused_args_func_info(PredArity),
-        Answer = unused_args(UnusedArgs),
 
-        analysis.lookup_results(AnalysisInfo0, PredModule, FuncId,
+        module_name_func_id_from_pred_info(OrigPredInfo, ProcId, ModuleId,
+            FuncId),
+        analysis.lookup_results(AnalysisInfo0, ModuleId, FuncId,
             IntermodResultsTriples : list(analysis_result(unused_args_call,
                 unused_args_answer))),
         IntermodOldAnswers = list.map((func(R) = R ^ ar_answer),
             IntermodResultsTriples),
+
+        PredArity = pred_info_orig_arity(OrigPredInfo),
+        FuncInfo = unused_args_func_info(PredArity),
+        Answer = unused_args(UnusedArgs),
+
         FilterUnused = (pred(VersionAnswer::in) is semidet :-
             VersionAnswer \= Answer,
             VersionAnswer \= unused_args([]),
             more_precise_than(FuncInfo, Answer, VersionAnswer)
         ),
         IntermodOldArgLists = list.map(get_unused_args,
-            list.filter(FilterUnused, IntermodOldAnswers)),
-
-        % 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.
-        globals.lookup_bool_option(Globals, make_analysis_registry,
-            MakeAnalysisRegistry),
-        ( 
-            MakeAnalysisRegistry = yes,
-            procedure_is_exported(!.ModuleInfo, OrigPredInfo, ProcId),
-            not is_unify_or_compare_pred(OrigPredInfo)
-            % XXX What about class instance methods and predicates used
-            %     for type specialization.  (These are a problem for 
-            %     intermodule-optimization; they may not be here.)
-            %     (See exception_analysis.should_write_exception_info/4).
-        ->
-            analysis.record_result(PredModule, FuncId, unused_args_call,
-                Answer, optimal, AnalysisInfo0, AnalysisInfo)
-        ;
-            AnalysisInfo = AnalysisInfo0
-        ),
-        module_info_set_analysis_info(AnalysisInfo, !ModuleInfo)
+            list.filter(FilterUnused, IntermodOldAnswers))
     ;
         Intermod = no,
         IntermodResultsTriples = [],
@@ -1907,6 +1863,43 @@ format_arg_list_2(First, List) = Pieces 
 
 %-----------------------------------------------------------------------------%
 
+:- pred maybe_record_intermod_unused_args(module_info::in, unused_arg_info::in,
+    pred_id::in, analysis_info::in, analysis_info::out) is det.
+
+maybe_record_intermod_unused_args(ModuleInfo, UnusedArgInfo, PredId,
+        !AnalysisInfo) :-
+    module_info_pred_info(ModuleInfo, PredId, PredInfo),
+    ProcIds = pred_info_procids(PredInfo),
+    list.foldl(
+        maybe_record_intermod_unused_args_2(ModuleInfo, UnusedArgInfo,
+            PredId, PredInfo),
+        ProcIds, !AnalysisInfo).
+
+:- pred maybe_record_intermod_unused_args_2(module_info::in,
+    unused_arg_info::in, pred_id::in, pred_info::in, proc_id::in,
+    analysis_info::in, analysis_info::out) is det.
+
+maybe_record_intermod_unused_args_2(ModuleInfo, UnusedArgInfo,  
+        PredId, PredInfo, ProcId, !AnalysisInfo) :-
+    (
+        procedure_is_exported(ModuleInfo, PredInfo, ProcId),
+        not is_unify_or_compare_pred(PredInfo)
+    ->
+        PPId = proc(PredId, ProcId),
+        ( map.search(UnusedArgInfo, PPId, UnusedArgs) ->
+            Answer = unused_args(UnusedArgs)
+        ;
+            Answer = unused_args([])
+        ),
+        module_name_func_id(ModuleInfo, PPId, ModuleName, FuncId),
+        record_result(ModuleName, FuncId, unused_args_call, Answer, optimal,
+            !AnalysisInfo)
+    ;
+        true
+    ).
+
+%-----------------------------------------------------------------------------%
+
     % If a procedure in this module calls a procedure from another module,
     % then we assume that this module depends on the analysis results of that
     % other procedure.
@@ -1925,28 +1918,30 @@ format_arg_list_2(First, List) = Pieces 
 record_intermod_dependencies(ModuleInfo, CallerPredProcId,
         !AnalysisInfo) :-
     module_info_pred_proc_info(ModuleInfo, CallerPredProcId,
-        CallerPredInfo, CallerProcInfo),
-    ( not pred_info_is_imported(CallerPredInfo) ->
-        CallerModule = pred_info_module(CallerPredInfo),
-        proc_info_get_goal(CallerProcInfo, Goal),
-        pred_proc_ids_from_goal(Goal, CalleePredProcIds),
-        list.foldl(record_intermod_dependencies_2(ModuleInfo, CallerModule),
-            CalleePredProcIds, !AnalysisInfo)
-    ;
-        true
-    ).
+        _CallerPredInfo, CallerProcInfo),
+    proc_info_get_goal(CallerProcInfo, Goal),
+    pred_proc_ids_from_goal(Goal, CalleePredProcIds),
+    list.foldl(record_intermod_dependencies_2(ModuleInfo),
+        CalleePredProcIds, !AnalysisInfo).
 
-:- pred record_intermod_dependencies_2(module_info::in, module_name::in,
-    pred_proc_id::in, analysis_info::in, analysis_info::out) is det.
+:- pred record_intermod_dependencies_2(module_info::in, pred_proc_id::in,
+    analysis_info::in, analysis_info::out) is det.
 
-record_intermod_dependencies_2(ModuleInfo, CallerModule,
+record_intermod_dependencies_2(ModuleInfo, 
         CalleePredProcId @ proc(CalleePredId, _), !AnalysisInfo) :-
     module_info_pred_info(ModuleInfo, CalleePredId, CalleePredInfo),
-    ( pred_info_is_imported(CalleePredInfo) ->
-        module_name_func_id(ModuleInfo, CalleePredProcId,
-            CalleeModule, CalleeFuncId),
-        analysis.record_dependency(CallerModule, analysis_name,
-            CalleeModule, CalleeFuncId, unused_args_call, !AnalysisInfo)
+    (
+        pred_info_is_imported_not_external(CalleePredInfo),
+        not is_unify_or_compare_pred(CalleePredInfo)
+    ->
+        module_name_func_id(ModuleInfo, CalleePredProcId, CalleeModule,
+            CalleeFuncId),
+        Call = unused_args_call,
+        Answer = _ : unused_args_answer,
+        get_func_info(ModuleInfo, CalleeModule, CalleeFuncId, Call, Answer,
+            FuncInfo),
+        record_dependency(CalleeModule, CalleeFuncId, FuncInfo, Call, Answer,
+            !AnalysisInfo)
     ;
         true
     ).
Index: tests/Mmakefile
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/Mmakefile,v
retrieving revision 1.14
diff -u -p -r1.14 Mmakefile
--- tests/Mmakefile	28 Jun 2006 04:46:21 -0000	1.14
+++ tests/Mmakefile	3 Jun 2008 07:32:27 -0000
@@ -2,6 +2,7 @@ THIS_DIR=tests
 PROGS=
 TESTS=
 SUBDIRS = \
+	analysis \
 	benchmarks \
 	debugger \
 	dppd \
Index: tests/analysis/Mmakefile
===================================================================
RCS file: tests/analysis/Mmakefile
diff -N tests/analysis/Mmakefile
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/Mmakefile	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,27 @@
+#-----------------------------------------------------------------------------#
+
+THIS_DIR = analysis
+
+#-----------------------------------------------------------------------------#
+
+SUBDIRS = \
+	excp \
+	ext \
+	reuse \
+	sharing \
+	table \
+	trail \
+	unused_args
+
+# These tests only work if the workspace was compiled with `--use-subdirs'.
+ifneq ($(origin WORKSPACE),undefined)
+    ifeq ($(shell [ -d $(WORKSPACE)/library/Mercury ] || echo cannot_run),cannot_run)
+    	SUBDIRS =
+    endif
+endif
+
+TESTS=
+TESTS_DIR=..
+include $(TESTS_DIR)/Mmake.common
+
+#-----------------------------------------------------------------------------#
Index: tests/analysis/common.sh
===================================================================
RCS file: tests/analysis/common.sh
diff -N tests/analysis/common.sh
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/common.sh	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,50 @@
+# vim: ft=sh ts=8 sts=4 sw=4 et
+#-----------------------------------------------------------------------------#
+# Common functions shared by the test scripts under this directory.
+
+MC=${MC:-mmc}
+MMCMAKE="$MC --make"
+
+failed () {
+    exit 1
+}
+
+check_result () {
+    # args: file pattern
+    if ! grep -q -e "$2" Mercury/analysiss/$1.analysis
+    then
+        failed
+    fi
+}
+
+check_statuses () {
+    case "`cat Mercury/analysis_statuss/* | tr -d '\n'`" in
+        $1) ;;
+        *) failed
+    esac
+}
+
+check_no_requests () {
+    case "`ls Mercury/requests`" in
+        "") ;;
+        *) failed
+    esac
+}
+
+check_request () {
+    # args: file pattern
+    if ! grep -q -e "$2" Mercury/requests/$1.request
+    then
+        failed
+    fi
+}
+
+check_imdg () {
+    # args: file pattern
+    if ! grep -q -e "$2" Mercury/imdgs/$1.imdg
+    then
+        failed
+    fi
+}
+
+#-----------------------------------------------------------------------------#
Index: tests/analysis/excp/Mercury.options
===================================================================
RCS file: tests/analysis/excp/Mercury.options
diff -N tests/analysis/excp/Mercury.options
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/excp/Mercury.options	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1 @@
+MCFLAGS = --intermodule-analysis --analyse-exceptions
Index: tests/analysis/excp/Mmakefile
===================================================================
RCS file: tests/analysis/excp/Mmakefile
diff -N tests/analysis/excp/Mmakefile
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/excp/Mmakefile	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,19 @@
+#-----------------------------------------------------------------------------#
+
+THIS_DIR = analysis/excp
+
+#-----------------------------------------------------------------------------#
+
+SUBDIRS=
+TESTS=excp_m1-nodepend
+TESTS_DIR=../..
+include $(TESTS_DIR)/Mmake.common
+
+excp_m1.runtest:
+	MC=$(MC) ./excp_runtest.sh
+
+realclean_local:
+	$(RM) excp_m1.m
+	$(RM) -r Mercury
+
+#-----------------------------------------------------------------------------#
Index: tests/analysis/excp/excp_m1.m.exception
===================================================================
RCS file: tests/analysis/excp/excp_m1.m.exception
diff -N tests/analysis/excp/excp_m1.m.exception
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/excp/excp_m1.m.exception	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,36 @@
+%-----------------------------------------------------------------------------%
+
+:- module excp_m1.
+:- interface.
+
+:- pred aaa(int::in) is det.
+
+:- pred aaa2(int::in) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module excp_m2.
+
+:- import_module require.
+
+%-----------------------------------------------------------------------------%
+
+:- pragma no_inline(aaa/1).
+
+aaa(N) :-
+    bbb(N).
+
+:- pragma no_inline(aaa2/1).
+
+aaa2(N) :-
+    ( N = 0 ->
+        error("zero")
+    ;
+        true
+    ).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/excp/excp_m1.m.no_exception
===================================================================
RCS file: tests/analysis/excp/excp_m1.m.no_exception
diff -N tests/analysis/excp/excp_m1.m.no_exception
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/excp/excp_m1.m.no_exception	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,31 @@
+%-----------------------------------------------------------------------------%
+
+:- module excp_m1.
+:- interface.
+
+:- pred aaa(int::in) is det.
+
+:- pred aaa2(int::in) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module excp_m2.
+
+:- import_module require.
+
+%-----------------------------------------------------------------------------%
+
+:- pragma no_inline(aaa/1).
+
+aaa(N) :-
+    bbb(N).
+
+:- pragma no_inline(aaa2/1).
+
+aaa2(_).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/excp/excp_m2.m
===================================================================
RCS file: tests/analysis/excp/excp_m2.m
diff -N tests/analysis/excp/excp_m2.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/excp/excp_m2.m	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,23 @@
+%-----------------------------------------------------------------------------%
+
+:- module excp_m2.
+:- interface.
+
+:- pred bbb(int::in) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module excp_m3.
+
+%-----------------------------------------------------------------------------%
+
+:- pragma no_inline(bbb/1).
+
+bbb(N) :-
+    ccc(N).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/excp/excp_m3.m
===================================================================
RCS file: tests/analysis/excp/excp_m3.m
diff -N tests/analysis/excp/excp_m3.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/excp/excp_m3.m	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,23 @@
+%-----------------------------------------------------------------------------%
+
+:- module excp_m3.
+:- interface.
+
+:- pred ccc(int::in) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module excp_m1.
+
+%-----------------------------------------------------------------------------%
+
+:- pragma no_inline(ccc/1).
+
+ccc(N) :-
+    aaa2(N).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/excp/excp_runtest.sh
===================================================================
RCS file: tests/analysis/excp/excp_runtest.sh
diff -N tests/analysis/excp/excp_runtest.sh
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/excp/excp_runtest.sh	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,69 @@
+#!/bin/sh
+# vim: ft=sh ts=8 sts=4 sw=4 et
+#-----------------------------------------------------------------------------#
+# Test exception analysis with intermodule analysis framework.
+
+source ../common.sh
+
+set -e
+set -x
+
+rm -rf Mercury
+
+: Step 1
+
+cat excp_m1.m.no_exception > excp_m1.m
+$MMCMAKE excp_m1.analyse --analysis-repeat 0 || failed
+
+check_result excp_m1 'exception.*aaa.*may_throw(user_exception)'
+check_result excp_m1 'exception.*aaa2.*will_not_throw'
+check_result excp_m2 'exception.*bbb.*may_throw(user_exception)'
+check_result excp_m3 'exception.*ccc.*will_not_throw'
+check_statuses 'suboptimal.suboptimal.optimal.'
+check_no_requests
+
+: Step 2
+
+$MMCMAKE excp_m1.analyse --analysis-repeat 3 || failed
+
+check_result excp_m1 'exception.*aaa.*will_not_throw'
+check_result excp_m1 'exception.*aaa2.*will_not_throw'
+check_result excp_m2 'exception.*bbb.*will_not_throw'
+check_result excp_m3 'exception.*ccc.*will_not_throw'
+check_statuses 'optimal.optimal.optimal.'
+check_no_requests
+check_imdg excp_m2 'excp_m1.*exception.*bbb'
+check_imdg excp_m3 'excp_m2.*exception.*ccc'
+check_imdg excp_m1 'excp_m3.*exception.*aaa'
+
+: Step 3
+
+sleep 1
+cat excp_m1.m.exception > excp_m1.m
+$MMCMAKE excp_m1.analyse --analysis-repeat 0 || failed
+
+check_result excp_m1 'exception.*aaa.*may_throw(user_exception)'
+check_result excp_m1 'exception.*aaa2.*may_throw(user_exception)'
+check_result excp_m2 'exception.*bbb.*may_throw(user_exception)'
+check_result excp_m3 'exception.*ccc.*may_throw(user_exception)'
+check_statuses 'optimal.optimal.optimal.'
+check_no_requests
+
+: Step 4
+
+sleep 1
+cat excp_m1.m.no_exception > excp_m1.m
+$MMCMAKE excp_m1.analyse --analysis-repeat 3 || failed
+
+check_result excp_m1 'exception.*aaa.*will_not_throw'
+check_result excp_m1 'exception.*aaa2.*will_not_throw'
+check_result excp_m2 'exception.*bbb.*will_not_throw'
+check_result excp_m3 'exception.*ccc.*will_not_throw'
+check_statuses 'optimal.optimal.optimal.'
+check_no_requests
+
+: Succeeded
+
+exit 0
+
+#-----------------------------------------------------------------------------#
Index: tests/analysis/ext/Mercury.options
===================================================================
RCS file: tests/analysis/ext/Mercury.options
diff -N tests/analysis/ext/Mercury.options
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/ext/Mercury.options	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,8 @@
+MCFLAGS = --intermodule-analysis
+
+MCFLAGS-ext = --ctgc
+MCFLAGS-ext += --analyse-exceptions
+MCFLAGS-ext += --use-trail --analyse-trail-usage
+MCFLAGS-ext += --optimise-unused-args
+
+MCFLAGS-ext2 = --grade none.mmsc --analyse-mm-tabling
Index: tests/analysis/ext/Mmakefile
===================================================================
RCS file: tests/analysis/ext/Mmakefile
diff -N tests/analysis/ext/Mmakefile
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/ext/Mmakefile	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,23 @@
+#-----------------------------------------------------------------------------#
+
+THIS_DIR = analysis/external
+
+#-----------------------------------------------------------------------------#
+
+SUBDIRS=
+TESTS = \
+	ext-nodepend \
+	ext2-nodepend
+TESTS_DIR=../..
+include $(TESTS_DIR)/Mmake.common
+
+ext.runtest:
+	MC=$(MC) ./ext_runtest.sh
+
+ext2.runtest:
+	MC=$(MC) ./ext2_runtest.sh
+
+realclean_local:
+	$(RM) -r Mercury
+
+#-----------------------------------------------------------------------------#
Index: tests/analysis/ext/ext.m
===================================================================
RCS file: tests/analysis/ext/ext.m
diff -N tests/analysis/ext/ext.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/ext/ext.m	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,27 @@
+% Analysis results should be written out for exported `:- external' predicates.
+% Importing modules don't care how those procedures are implemented, so results
+% should exist.
+
+:- module ext.
+:- interface.
+
+:- pred foo(t::in, t::out) is det.
+
+:- pred bar(t::in, t::out) is det.
+
+:- type t
+    --->    t(int, int).
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- external(foo/2).
+
+% For comparison.
+:- pragma no_inline(bar/2).
+bar(X, X).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/ext/ext2.m
===================================================================
RCS file: tests/analysis/ext/ext2.m
diff -N tests/analysis/ext/ext2.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/ext/ext2.m	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,25 @@
+% Same as ext.m but tests trail usage analysis separately.
+
+:- module ext2.
+:- interface.
+
+:- pred foo(t::in, t::out) is det.
+
+:- pred bar(t::in, t::out) is det.
+
+:- type t
+    --->    t(int, int).
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- external(foo/2).
+
+% For comparison.
+:- pragma no_inline(bar/2).
+bar(X, X).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/ext/ext2_runtest.sh
===================================================================
RCS file: tests/analysis/ext/ext2_runtest.sh
diff -N tests/analysis/ext/ext2_runtest.sh
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/ext/ext2_runtest.sh	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,23 @@
+#!/bin/sh
+# vim: ft=sh ts=8 sts=4 sw=4 et
+#-----------------------------------------------------------------------------#
+# Test handling of :- external procedures with intermodule analysis.
+
+source ../common.sh
+
+set -e
+set -x
+
+rm -rf Mercury
+
+$MMCMAKE ext2.analyse --analysis-repeat 0 || failed
+
+check_result ext2 'mm_tabling.*foo'
+check_statuses 'optimal.'
+check_no_requests
+
+: Succeeded
+
+exit 0
+
+#-----------------------------------------------------------------------------#
Index: tests/analysis/ext/ext_runtest.sh
===================================================================
RCS file: tests/analysis/ext/ext_runtest.sh
diff -N tests/analysis/ext/ext_runtest.sh
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/ext/ext_runtest.sh	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,27 @@
+#!/bin/sh
+# vim: ft=sh ts=8 sts=4 sw=4 et
+#-----------------------------------------------------------------------------#
+# Test handling of :- external procedures with intermodule analysis.
+
+source ../common.sh
+
+set -e
+set -x
+
+rm -rf Mercury
+
+$MMCMAKE ext.analyse --analysis-repeat 0 || failed
+
+check_result ext 'exception.*foo'
+check_result ext 'structure_reuse.*foo'
+check_result ext 'structure_sharing.*foo'
+check_result ext 'trail.*foo'
+check_result ext 'unused_args.*foo'
+check_statuses 'optimal.'
+check_no_requests
+
+: Succeeded
+
+exit 0
+
+#-----------------------------------------------------------------------------#
Index: tests/analysis/sharing/Mercury.options
===================================================================
RCS file: tests/analysis/sharing/Mercury.options
diff -N tests/analysis/sharing/Mercury.options
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/sharing/Mercury.options	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1 @@
+MCFLAGS = --intermodule-analysis --structure-sharing
Index: tests/analysis/sharing/Mmakefile
===================================================================
RCS file: tests/analysis/sharing/Mmakefile
diff -N tests/analysis/sharing/Mmakefile
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/sharing/Mmakefile	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,19 @@
+#-----------------------------------------------------------------------------#
+
+THIS_DIR = analysis/structure_sharing
+
+#-----------------------------------------------------------------------------#
+
+SUBDIRS=
+TESTS=sharing_m1-nodepend
+TESTS_DIR=../..
+include $(TESTS_DIR)/Mmake.common
+
+sharing_m1.runtest:
+	MC=$(MC) ./sharing_runtest.sh
+
+realclean_local:
+	$(RM) sharing_m1.m
+	$(RM) -r Mercury
+
+#-----------------------------------------------------------------------------#
Index: tests/analysis/sharing/sharing_m1.m.no_share
===================================================================
RCS file: tests/analysis/sharing/sharing_m1.m.no_share
diff -N tests/analysis/sharing/sharing_m1.m.no_share
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/sharing/sharing_m1.m.no_share	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,27 @@
+%-----------------------------------------------------------------------------%
+
+:- module sharing_m1.
+:- interface.
+
+:- import_module sharing_m2.
+
+:- pred aaa(foo::in, foo::out) is det.
+
+:- pred aaa2(foo::in, foo::out) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- pragma no_inline(aaa/2).
+
+aaa(N, M) :-
+    bbb(N, M).
+
+:- pragma no_inline(aaa2/2).
+
+aaa2(_X, foo(0, 0)).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/sharing/sharing_m1.m.share
===================================================================
RCS file: tests/analysis/sharing/sharing_m1.m.share
diff -N tests/analysis/sharing/sharing_m1.m.share
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/sharing/sharing_m1.m.share	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,27 @@
+%-----------------------------------------------------------------------------%
+
+:- module sharing_m1.
+:- interface.
+
+:- import_module sharing_m2.
+
+:- pred aaa(foo::in, foo::out) is det.
+
+:- pred aaa2(foo::in, foo::out) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- pragma no_inline(aaa/2).
+
+aaa(N, M) :-
+    bbb(N, M).
+
+:- pragma no_inline(aaa2/2).
+
+aaa2(X, X).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/sharing/sharing_m2.m
===================================================================
RCS file: tests/analysis/sharing/sharing_m2.m
diff -N tests/analysis/sharing/sharing_m2.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/sharing/sharing_m2.m	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,26 @@
+%-----------------------------------------------------------------------------%
+
+:- module sharing_m2.
+:- interface.
+
+:- type foo
+    --->    foo(int, int).
+
+:- pred bbb(foo::in, foo::out) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module sharing_m3.
+
+%-----------------------------------------------------------------------------%
+
+:- pragma no_inline(bbb/2).
+
+bbb(N, M) :-
+    ccc(N, M).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/sharing/sharing_m3.m
===================================================================
RCS file: tests/analysis/sharing/sharing_m3.m
diff -N tests/analysis/sharing/sharing_m3.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/sharing/sharing_m3.m	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,25 @@
+%-----------------------------------------------------------------------------%
+
+:- module sharing_m3.
+:- interface.
+
+:- import_module sharing_m2.
+
+:- pred ccc(foo::in, foo::out) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module sharing_m1.
+
+%-----------------------------------------------------------------------------%
+
+:- pragma no_inline(ccc/2).
+
+ccc(N, M) :-
+    aaa2(N, M).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/sharing/sharing_runtest.sh
===================================================================
RCS file: tests/analysis/sharing/sharing_runtest.sh
diff -N tests/analysis/sharing/sharing_runtest.sh
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/sharing/sharing_runtest.sh	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,69 @@
+#!/bin/sh
+# vim: ft=sh ts=8 sts=4 sw=4 et
+#-----------------------------------------------------------------------------#
+# Test structure sharing analysis with intermodule analysis framework.
+
+source ../common.sh
+
+set -e
+set -x
+
+rm -rf Mercury
+
+: Step 1
+
+cat sharing_m1.m.no_share > sharing_m1.m
+$MMCMAKE sharing_m1.analyse --analysis-repeat 0 || failed
+
+check_result sharing_m1 'sharing.*aaa.*"t"'
+check_result sharing_m1 'sharing.*aaa2.*"b"'
+check_result sharing_m2 'sharing.*bbb.*"t"'
+check_result sharing_m3 'sharing.*ccc.*"b"'
+check_statuses 'suboptimal.suboptimal.optimal.'
+check_no_requests
+
+: Step 2
+
+$MMCMAKE sharing_m1.analyse --analysis-repeat 3 || failed
+
+check_result sharing_m1 'sharing.*aaa.*"b"'
+check_result sharing_m1 'sharing.*aaa2.*"b"'
+check_result sharing_m2 'sharing.*bbb.*"b"'
+check_result sharing_m3 'sharing.*ccc.*"b"'
+check_statuses 'optimal.optimal.optimal.'
+check_no_requests
+check_imdg sharing_m2 'sharing_m1.*sharing.*bbb'
+check_imdg sharing_m3 'sharing_m2.*sharing.*ccc'
+check_imdg sharing_m1 'sharing_m3.*sharing.*aaa2'
+
+: Step 3
+
+sleep 1
+cat sharing_m1.m.share > sharing_m1.m
+$MMCMAKE sharing_m1.analyse --analysis-repeat 0 || failed
+
+check_result sharing_m1 'sharing.*aaa.*cel.*\[\].*cel.*\[\]'
+check_result sharing_m1 'sharing.*aaa2.*cel.*\[\].*cel.*\[\]'
+check_result sharing_m2 'sharing.*bbb.*cel.*\[\].*cel.*\[\]'
+check_result sharing_m3 'sharing.*ccc.*cel.*\[\].*cel.*\[\]'
+check_statuses 'optimal.optimal.optimal.'
+check_no_requests
+
+: Step 4
+
+sleep 1
+cat sharing_m1.m.no_share > sharing_m1.m
+$MMCMAKE sharing_m1.analyse --analysis-repeat 3 || failed
+
+check_result sharing_m1 'sharing.*aaa.*"b"'
+check_result sharing_m1 'sharing.*aaa2.*"b"'
+check_result sharing_m2 'sharing.*bbb.*"b"'
+check_result sharing_m3 'sharing.*ccc.*"b"'
+check_statuses 'optimal.optimal.optimal.'
+check_no_requests
+
+: Succeeded
+
+exit 0
+
+#-----------------------------------------------------------------------------#
Index: tests/analysis/table/Mercury.options
===================================================================
RCS file: tests/analysis/table/Mercury.options
diff -N tests/analysis/table/Mercury.options
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/table/Mercury.options	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,2 @@
+MCFLAGS = --intermodule-analysis
+MCFLAGS += --grade none.mmsc --analyse-mm-tabling
Index: tests/analysis/table/Mmakefile
===================================================================
RCS file: tests/analysis/table/Mmakefile
diff -N tests/analysis/table/Mmakefile
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/table/Mmakefile	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,19 @@
+#-----------------------------------------------------------------------------#
+
+THIS_DIR = analysis/table
+
+#-----------------------------------------------------------------------------#
+
+SUBDIRS=
+TESTS=table_m1-nodepend
+TESTS_DIR=../..
+include $(TESTS_DIR)/Mmake.common
+
+table_m1.runtest:
+	MC=$(MC) ./table_runtest.sh
+
+realclean_local:
+	$(RM) table_m1.m
+	$(RM) -r Mercury
+
+#-----------------------------------------------------------------------------#
Index: tests/analysis/table/table_m1.m.no_tabling
===================================================================
RCS file: tests/analysis/table/table_m1.m.no_tabling
diff -N tests/analysis/table/table_m1.m.no_tabling
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/table/table_m1.m.no_tabling	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,32 @@
+%-----------------------------------------------------------------------------%
+
+:- module table_m1.
+:- interface.
+
+:- pred aaa(int::in) is det.
+
+:- pred aaa2(int::in, int::out) is semidet.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module table_m2.
+
+:- import_module int.
+
+%-----------------------------------------------------------------------------%
+
+:- pragma no_inline(aaa/1).
+
+aaa(N) :-
+    bbb(N).
+
+:- pragma no_inline(aaa2/2).
+
+aaa2(N, M) :-
+    aaa2(N - 1, M).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/table/table_m1.m.tabling
===================================================================
RCS file: tests/analysis/table/table_m1.m.tabling
diff -N tests/analysis/table/table_m1.m.tabling
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/table/table_m1.m.tabling	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,34 @@
+%-----------------------------------------------------------------------------%
+
+:- module table_m1.
+:- interface.
+
+:- pred aaa(int::in) is det.
+
+:- pred aaa2(int::in, int::out) is nondet.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module table_m2.
+
+:- import_module int.
+:- import_module require.
+
+%-----------------------------------------------------------------------------%
+
+:- pragma no_inline(aaa/1).
+
+aaa(N) :-
+    bbb(N).
+
+:- pragma no_inline(aaa2/2).
+:- pragma minimal_model(aaa2/2).
+
+aaa2(N, M) :-
+    aaa2(N, M).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/table/table_m2.m
===================================================================
RCS file: tests/analysis/table/table_m2.m
diff -N tests/analysis/table/table_m2.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/table/table_m2.m	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,23 @@
+%-----------------------------------------------------------------------------%
+
+:- module table_m2.
+:- interface.
+
+:- pred bbb(int::in) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module table_m3.
+
+%-----------------------------------------------------------------------------%
+
+:- pragma no_inline(bbb/1).
+
+bbb(N) :-
+    ccc(N).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/table/table_m3.m
===================================================================
RCS file: tests/analysis/table/table_m3.m
diff -N tests/analysis/table/table_m3.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/table/table_m3.m	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,27 @@
+%-----------------------------------------------------------------------------%
+
+:- module table_m3.
+:- interface.
+
+:- pred ccc(int::in) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module table_m1.
+
+%-----------------------------------------------------------------------------%
+
+:- pragma no_inline(ccc/1).
+
+ccc(N) :-
+    ( aaa2(N, _) ->
+        true
+    ;
+        true
+    ).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/table/table_runtest.sh
===================================================================
RCS file: tests/analysis/table/table_runtest.sh
diff -N tests/analysis/table/table_runtest.sh
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/table/table_runtest.sh	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,69 @@
+#!/bin/sh
+# vim: ft=sh ts=8 sts=4 sw=4 et
+#-----------------------------------------------------------------------------#
+# Test --analyse-mm-tabling with the intermodule analysis framework.
+
+source ../common.sh
+
+set -e
+set -x
+
+rm -rf Mercury
+
+: Step 1
+
+cat table_m1.m.no_tabling > table_m1.m
+$MMCMAKE table_m1.analyse --analysis-repeat 0 || failed
+
+check_result table_m1 'tabling.*aaa.*mm_tabled_may_call'
+check_result table_m1 'tabling.*aaa2.*mm_tabled_will_not_call'
+check_result table_m2 'tabling.*bbb.*mm_tabled_may_call'
+check_result table_m3 'tabling.*ccc.*mm_tabled_will_not_call'
+check_statuses 'suboptimal.suboptimal.optimal.'
+check_no_requests
+
+: Step 2
+
+$MMCMAKE table_m1.analyse --analysis-repeat 2 || failed
+
+check_result table_m1 'tabling.*aaa.*mm_tabled_will_not_call'
+check_result table_m1 'tabling.*aaa2.*mm_tabled_will_not_call'
+check_result table_m2 'tabling.*bbb.*mm_tabled_will_not_call'
+check_result table_m3 'tabling.*ccc.*mm_tabled_will_not_call'
+check_statuses 'optimal.optimal.optimal.'
+check_no_requests
+check_imdg table_m2 'table_m1.*tabling.*bbb'
+check_imdg table_m3 'table_m2.*tabling.*ccc'
+check_imdg table_m1 'table_m3.*tabling.*aaa'
+
+: Step 3
+
+sleep 1
+cat table_m1.m.tabling > table_m1.m
+$MMCMAKE table_m1.analyse --analysis-repeat 0 || failed
+
+check_result table_m1 'tabling.*aaa.*mm_tabled_may_call'
+check_result table_m1 'tabling.*aaa2.*mm_tabled_may_call'
+check_result table_m2 'tabling.*bbb.*mm_tabled_may_call'
+check_result table_m3 'tabling.*ccc.*mm_tabled_may_call'
+check_statuses 'optimal.optimal.optimal.'
+check_no_requests
+
+: Step 4
+
+sleep 1
+cat table_m1.m.no_tabling > table_m1.m
+$MMCMAKE table_m1.analyse --analysis-repeat 3 || failed
+
+check_result table_m1 'tabling.*aaa.*mm_tabled_will_not_call'
+check_result table_m1 'tabling.*aaa2.*mm_tabled_will_not_call'
+check_result table_m2 'tabling.*bbb.*mm_tabled_will_not_call'
+check_result table_m3 'tabling.*ccc.*mm_tabled_will_not_call'
+check_statuses 'optimal.optimal.optimal.'
+check_no_requests
+
+: Succeeded
+
+exit 0
+
+#-----------------------------------------------------------------------------#
Index: tests/analysis/trail/Mercury.options
===================================================================
RCS file: tests/analysis/trail/Mercury.options
diff -N tests/analysis/trail/Mercury.options
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/trail/Mercury.options	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,2 @@
+MCFLAGS = --intermodule-analysis
+MCFLAGS += --use-trail --analyse-trail-usage
Index: tests/analysis/trail/Mmakefile
===================================================================
RCS file: tests/analysis/trail/Mmakefile
diff -N tests/analysis/trail/Mmakefile
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/trail/Mmakefile	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,19 @@
+#-----------------------------------------------------------------------------#
+
+THIS_DIR = analysis/trail
+
+#-----------------------------------------------------------------------------#
+
+SUBDIRS=
+TESTS=trail_m1-nodepend
+TESTS_DIR=../..
+include $(TESTS_DIR)/Mmake.common
+
+trail_m1.runtest:
+	MC=$(MC) ./trail_runtest.sh
+
+realclean_local:
+	$(RM) trail_m1.m
+	$(RM) -r Mercury
+
+#-----------------------------------------------------------------------------#
Index: tests/analysis/trail/trail_m1.m.no_trail
===================================================================
RCS file: tests/analysis/trail/trail_m1.m.no_trail
diff -N tests/analysis/trail/trail_m1.m.no_trail
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/trail/trail_m1.m.no_trail	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,31 @@
+%-----------------------------------------------------------------------------%
+
+:- module trail_m1.
+:- interface.
+
+:- pred aaa1(int::in) is det.
+
+:- pred aaa2(int::in, int::out) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module trail_m2.
+
+:- import_module require.
+
+%-----------------------------------------------------------------------------%
+
+:- pragma no_inline(aaa1/1).
+
+aaa1(N) :-
+    bbb(N).
+
+:- pragma no_inline(aaa2/2).
+
+aaa2(N, N).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/trail/trail_m1.m.trail
===================================================================
RCS file: tests/analysis/trail/trail_m1.m.trail
diff -N tests/analysis/trail/trail_m1.m.trail
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/trail/trail_m1.m.trail	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,34 @@
+%-----------------------------------------------------------------------------%
+
+:- module trail_m1.
+:- interface.
+
+:- pred aaa1(int::in) is det.
+
+:- pred aaa2(int::in, int::out) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module trail_m2.
+
+%-----------------------------------------------------------------------------%
+
+:- pragma no_inline(aaa1/1).
+
+aaa1(N) :-
+    bbb(N).
+
+:- pragma no_inline(aaa2/2).
+
+:- pragma foreign_proc("C",
+    aaa2(N0::in, N::out),
+    [will_not_call_mercury, promise_pure, may_modify_trail],
+"
+    N = N0;
+").
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/trail/trail_m2.m
===================================================================
RCS file: tests/analysis/trail/trail_m2.m
diff -N tests/analysis/trail/trail_m2.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/trail/trail_m2.m	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,23 @@
+%-----------------------------------------------------------------------------%
+
+:- module trail_m2.
+:- interface.
+
+:- pred bbb(int::in) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module trail_m3.
+
+%-----------------------------------------------------------------------------%
+
+:- pragma no_inline(bbb/1).
+
+bbb(N) :-
+    ccc(N).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/trail/trail_m3.m
===================================================================
RCS file: tests/analysis/trail/trail_m3.m
diff -N tests/analysis/trail/trail_m3.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/trail/trail_m3.m	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,23 @@
+%-----------------------------------------------------------------------------%
+
+:- module trail_m3.
+:- interface.
+
+:- pred ccc(int::in) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module trail_m1.
+
+%-----------------------------------------------------------------------------%
+
+:- pragma no_inline(ccc/1).
+
+ccc(N) :-
+    aaa2(N, _).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/trail/trail_runtest.sh
===================================================================
RCS file: tests/analysis/trail/trail_runtest.sh
diff -N tests/analysis/trail/trail_runtest.sh
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/trail/trail_runtest.sh	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,69 @@
+#!/bin/sh
+# vim: ft=sh ts=8 sts=4 sw=4 et
+#-----------------------------------------------------------------------------#
+# Test trail usage analysis with the intermodule analysis framework.
+
+source ../common.sh
+
+set -e
+set -x
+
+rm -rf Mercury
+
+: Step 1
+
+cat trail_m1.m.no_trail > trail_m1.m
+$MMCMAKE trail_m1.analyse --analysis-repeat 0 || failed
+
+check_result trail_m1 'aaa1.*may_modify_trail'
+check_result trail_m1 'aaa2.*will_not_modify_trail'
+check_result trail_m2 'bbb.*may_modify_trail'
+check_result trail_m3 'ccc.*will_not_modify_trail'
+check_statuses 'suboptimal.suboptimal.optimal.'
+check_no_requests
+
+: Step 2
+
+$MMCMAKE trail_m1.analyse --analysis-repeat 2 || failed
+
+check_result trail_m1 'aaa1.*will_not_modify_trail'
+check_result trail_m1 'aaa2.*will_not_modify_trail'
+check_result trail_m2 'bbb.*will_not_modify_trail'
+check_result trail_m3 'ccc.*will_not_modify_trail'
+check_statuses 'optimal.optimal.optimal.'
+check_no_requests
+check_imdg trail_m2 'trail_m1.*trail.*bbb'
+check_imdg trail_m3 'trail_m2.*trail.*ccc'
+check_imdg trail_m1 'trail_m3.*trail.*aaa2'
+
+: Step 3
+
+sleep 1
+cat trail_m1.m.trail > trail_m1.m
+$MMCMAKE trail_m1.analyse --analysis-repeat 0 || failed
+
+check_result trail_m1 'aaa1.*may_modify_trail'
+check_result trail_m1 'aaa2.*may_modify_trail'
+check_result trail_m2 'bbb.*may_modify_trail'
+check_result trail_m3 'ccc.*may_modify_trail'
+check_statuses 'optimal.optimal.optimal.'
+check_no_requests
+
+: Step 4
+
+sleep 1
+cat trail_m1.m.no_trail > trail_m1.m
+$MMCMAKE trail_m1.analyse --analysis-repeat 3 || failed
+
+check_result trail_m1 'aaa1.*will_not_modify_trail'
+check_result trail_m1 'aaa2.*will_not_modify_trail'
+check_result trail_m2 'bbb.*will_not_modify_trail'
+check_result trail_m3 'ccc.*will_not_modify_trail'
+check_statuses 'optimal.optimal.optimal.'
+check_no_requests
+
+: Succeeded
+
+exit 0
+
+#-----------------------------------------------------------------------------#
Index: tests/analysis/unused_args/Mercury.options
===================================================================
RCS file: tests/analysis/unused_args/Mercury.options
diff -N tests/analysis/unused_args/Mercury.options
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/unused_args/Mercury.options	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1 @@
+MCFLAGS = --intermodule-analysis --optimise-unused-args
Index: tests/analysis/unused_args/Mmakefile
===================================================================
RCS file: tests/analysis/unused_args/Mmakefile
diff -N tests/analysis/unused_args/Mmakefile
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/unused_args/Mmakefile	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,19 @@
+#-----------------------------------------------------------------------------#
+
+THIS_DIR = analysis/unused_args
+
+#-----------------------------------------------------------------------------#
+
+SUBDIRS=
+TESTS=ua_m1-nodepend
+TESTS_DIR=../..
+include $(TESTS_DIR)/Mmake.common
+
+ua_m1.runtest:
+	MC=$(MC) ./unused_args_runtest.sh
+
+realclean_local:
+	$(RM) ua_m1.m
+	$(RM) -r Mercury
+
+#-----------------------------------------------------------------------------#
Index: tests/analysis/unused_args/ua_m1.m.no_unused_args
===================================================================
RCS file: tests/analysis/unused_args/ua_m1.m.no_unused_args
diff -N tests/analysis/unused_args/ua_m1.m.no_unused_args
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/unused_args/ua_m1.m.no_unused_args	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,29 @@
+%-----------------------------------------------------------------------------%
+
+:- module ua_m1.
+:- interface.
+
+:- pred aaa1(int::in, int::out) is det.
+
+:- pred aaa2(int::in, int::out) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module ua_m2.
+
+%-----------------------------------------------------------------------------%
+
+:- pragma no_inline(aaa1/2).
+
+aaa1(N, M) :-
+    bbb(N, M).
+
+:- pragma no_inline(aaa2/2).
+
+aaa2(N, N).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/unused_args/ua_m1.m.unused_args
===================================================================
RCS file: tests/analysis/unused_args/ua_m1.m.unused_args
diff -N tests/analysis/unused_args/ua_m1.m.unused_args
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/unused_args/ua_m1.m.unused_args	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,29 @@
+%-----------------------------------------------------------------------------%
+
+:- module ua_m1.
+:- interface.
+
+:- pred aaa1(int::in, int::out) is det.
+
+:- pred aaa2(int::in, int::out) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module ua_m2.
+
+%-----------------------------------------------------------------------------%
+
+:- pragma no_inline(aaa1/2).
+
+aaa1(N, M) :-
+    bbb(N, M).
+
+:- pragma no_inline(aaa2/2).
+
+aaa2(_, 10).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/unused_args/ua_m2.m
===================================================================
RCS file: tests/analysis/unused_args/ua_m2.m
diff -N tests/analysis/unused_args/ua_m2.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/unused_args/ua_m2.m	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,23 @@
+%-----------------------------------------------------------------------------%
+
+:- module ua_m2.
+:- interface.
+
+:- pred bbb(int::in, int::out) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module ua_m3.
+
+%-----------------------------------------------------------------------------%
+
+:- pragma no_inline(bbb/2).
+
+bbb(N, M) :-
+    ccc(N, M).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/unused_args/ua_m3.m
===================================================================
RCS file: tests/analysis/unused_args/ua_m3.m
diff -N tests/analysis/unused_args/ua_m3.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/unused_args/ua_m3.m	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,23 @@
+%-----------------------------------------------------------------------------%
+
+:- module ua_m3.
+:- interface.
+
+:- pred ccc(int::in, int::out) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module ua_m1.
+
+%-----------------------------------------------------------------------------%
+
+:- pragma no_inline(ccc/2).
+
+ccc(N, M) :-
+    aaa2(N, M).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
Index: tests/analysis/unused_args/unused_args_runtest.sh
===================================================================
RCS file: tests/analysis/unused_args/unused_args_runtest.sh
diff -N tests/analysis/unused_args/unused_args_runtest.sh
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/analysis/unused_args/unused_args_runtest.sh	3 Jun 2008 07:32:27 -0000
@@ -0,0 +1,102 @@
+#!/bin/sh
+# vim: ft=sh ts=8 sts=4 sw=4 et
+#-----------------------------------------------------------------------------#
+# Test unused argument optimisation with intermodule analysis framework.
+
+source ../common.sh
+
+set -e
+set -x
+
+rm -rf Mercury
+
+: Step 1
+
+# Start without unused arguments in aaa2.
+
+cat ua_m1.m.no_unused_args > ua_m1.m
+$MMCMAKE ua_m1.analyse --analysis-repeat 0 || failed
+
+check_result ua_m1 'aaa1.*"", ""'
+check_result ua_m1 'aaa2.*"", ""'
+check_result ua_m2 'bbb.*"", ""'
+check_result ua_m3 'ccc.*"", ""'
+check_statuses 'suboptimal.suboptimal.optimal.'
+check_no_requests
+
+: Step 2
+
+$MMCMAKE ua_m1.analyse --analysis-repeat 1 || failed
+
+check_result ua_m1 'aaa1.*"", ""'
+check_result ua_m1 'aaa2.*"", ""'
+check_result ua_m2 'bbb.*"", ""'
+check_result ua_m3 'ccc.*"", ""'
+check_statuses 'optimal.optimal.optimal.'
+check_no_requests
+check_imdg ua_m2 'ua_m1.*unused_args.*bbb'
+check_imdg ua_m3 'ua_m2.*unused_args.*ccc'
+check_imdg ua_m1 'ua_m3.*unused_args.*aaa2'
+
+: Step 3
+
+# Everything is fully analysed.
+# Now make aaa2 have one unused argument.
+
+sleep 1
+cat ua_m1.m.unused_args > ua_m1.m
+$MMCMAKE ua_m1.analyse --analysis-repeat 0 || failed
+
+check_result ua_m1 'aaa1.*"", ""'
+check_result ua_m1 'aaa2.*"", "1"'
+check_result ua_m2 'bbb.*"", ""'
+check_result ua_m3 'ccc.*"", ""'
+check_statuses 'optimal.optimal.suboptimal.'
+check_no_requests
+check_imdg ua_m2 'ua_m1.*unused_args.*bbb'
+check_imdg ua_m3 'ua_m2.*unused_args.*ccc'
+check_imdg ua_m1 'ua_m3.*unused_args.*aaa2'
+
+: Step 4
+
+$MMCMAKE ua_m1.analyse --analysis-repeat 1 || failed
+
+check_result ua_m1 'aaa1.*"", ""'
+check_result ua_m1 'aaa2.*"", "1"'
+check_result ua_m2 'bbb.*"", ""'
+check_result ua_m3 'ccc.*"", "1"'
+check_statuses 'optimal.suboptimal.optimal.'
+check_no_requests
+
+: Step 5
+
+$MMCMAKE ua_m1.analyse --analysis-repeat 2 || failed
+
+check_result ua_m1 'aaa1.*"", "1"'
+check_result ua_m1 'aaa2.*"", "1"'
+check_result ua_m2 'bbb.*"", "1"'
+check_result ua_m3 'ccc.*"", "1"'
+check_statuses 'optimal.optimal.optimal.'
+check_no_requests
+
+: Step 6
+
+# The unused argument is fully propagated.
+# Make the argument used again and watch everything recover.
+
+sleep 1
+cat ua_m1.m.no_unused_args > ua_m1.m
+$MMCMAKE ua_m1.analyse --analysis-repeat 0 || failed
+
+check_result ua_m1 'aaa1.*"", ""'
+check_result ua_m1 'aaa2.*"", ""'
+check_result ua_m2 'bbb.*"", ""'
+check_result ua_m3 'ccc.*"", ""'
+check_statuses 'optimal.optimal.optimal.'
+check_no_requests
+
+: Succeeded
+
+exit 0
+
+#-----------------------------------------------------------------------------#


--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list