[m-rev.] diff: make structure reuse analysis use analysis framework

Peter Wang novalazy at gmail.com
Wed May 7 15:07:55 AEST 2008


For post-commit review if anyone wants.

Branches: main

Make the structure reuse analysis able to use the intermodule analysis
framework.

compiler/hlds_pred.m:
	Keep the analysis status with the structure reuse domain in the
	proc_info.

compiler/hlds_out.m:
	Conform to the above.

compiler/mmc_analysis.m:
	Add structure reuse to the list of analyses.

compiler/structure_reuse.analysis.m:
	Add the usual code to interface an analysis pass with the analysis
	framework.

	Load reuse information about imported procedures from the analysis
	registry.

	Record reuse analysis results and dependencies to the analysis
	registry.

	We were not writing out results for `:- external' procedures even if
	they were exported; do that.

	Write out the results for type specialised procedures if making
	`.analysis' files, because we can, but not for `.opt' files, since we
	can't.

compiler/structure_reuse.direct.m:
	Add reuse results for `:- external' procedures to the reuse table so
	that they will be written out to `.opt' and `.analysis' files.

compiler/structure_reuse.domain.m:
	Keep the analysis status with the reuse_as in the reuse table.

	Change a semidet function to a predicate.

compiler/structure_reuse.indirect.m:
	Keep track of the procedures which we depended on during the analysis.

	Rename AnalysisInfo to IrInfo everywhere as AnalysisInfo usually
	refers to the analysis_info of the intermodule analysis framework.

compiler/structure_reuse.versions.m:
	Don't try to create reuse versions of imported procedures which may
	appear in the reuse table.

compiler/structure_sharing.analysis.m:
	Write out results for `:- external' procedures.

	Make sure not to write out results for unify/compare predicates
	(although it doesn't seem to happen anyway).

	Write out results for type specialised procedures to `.analysis'
	files but not `.opt' files.

compiler/structure_sharing.domain.m:
	Add a question to investigate later.

Index: compiler/hlds_out.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/hlds_out.m,v
retrieving revision 1.449
diff -u -r1.449 hlds_out.m
--- compiler/hlds_out.m	10 Apr 2008 04:12:42 -0000	1.449
+++ compiler/hlds_out.m	7 May 2008 05:04:50 -0000
@@ -3985,8 +3985,8 @@
         io.write_string("% Structure sharing: \n", !IO),
         (
             MaybeStructureSharing = yes(
-                structure_sharing_domain_and_status(Domain, _Status)),
-            dump_maybe_structure_sharing_domain(VarSet, TVarSet, yes(Domain),
+                structure_sharing_domain_and_status(SharingAs, _Status)),
+            dump_maybe_structure_sharing_domain(VarSet, TVarSet, yes(SharingAs),
                 !IO)
         ;
             MaybeStructureSharing = no,
@@ -4001,7 +4001,8 @@
         write_indent(Indent, !IO),
         io.write_string("% Structure reuse: \n", !IO),
         (
-            MaybeStructureReuse = yes(ReuseAs),
+            MaybeStructureReuse = yes(
+                structure_reuse_domain_and_status(ReuseAs, _ReuseStatus)),
             dump_maybe_structure_reuse_domain(VarSet, TVarSet, yes(ReuseAs),
                 !IO)
         ;
Index: compiler/hlds_pred.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/hlds_pred.m,v
retrieving revision 1.242
diff -u -r1.242 hlds_pred.m
--- compiler/hlds_pred.m	17 Apr 2008 04:21:50 -0000	1.242
+++ compiler/hlds_pred.m	7 May 2008 05:04:51 -0000
@@ -1854,6 +1854,12 @@
                 analysis_status
             ).
 
+:- type structure_reuse_domain_and_status
+    --->    structure_reuse_domain_and_status(
+                structure_reuse_domain,
+                analysis_status
+            ).
+
 :- type untuple_proc_info
     --->    untuple_proc_info(
                 map(prog_var, prog_vars)
@@ -2008,9 +2014,9 @@
     proc_info::out) is det.
 
 :- pred proc_info_get_structure_reuse(proc_info::in,
-    maybe(structure_reuse_domain)::out) is det.
+    maybe(structure_reuse_domain_and_status)::out) is det.
 
-:- pred proc_info_set_structure_reuse(structure_reuse_domain::in,
+:- pred proc_info_set_structure_reuse(structure_reuse_domain_and_status::in,
     proc_info::in, proc_info::out) is det.
 
 :- pred proc_info_get_imported_structure_reuse(proc_info::in,
@@ -2347,7 +2353,7 @@
 
 :- type structure_reuse_info
     --->    structure_reuse_info(
-                maybe_reuse           :: maybe(structure_reuse_domain),
+                maybe_reuse     :: maybe(structure_reuse_domain_and_status),
 
                 maybe_imported_reuse  :: maybe(imported_reuse)
                 % Records the reuse information from any `.opt' or
Index: compiler/mmc_analysis.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/mmc_analysis.m,v
retrieving revision 1.23
diff -u -r1.23 mmc_analysis.m
--- compiler/mmc_analysis.m	27 Mar 2008 02:29:42 -0000	1.23
+++ compiler/mmc_analysis.m	7 May 2008 05:04:51 -0000
@@ -54,6 +54,8 @@
 :- import_module transform_hlds.ctgc.
 :- import_module transform_hlds.ctgc.structure_sharing.
 :- import_module transform_hlds.ctgc.structure_sharing.analysis.
+:- import_module transform_hlds.ctgc.structure_reuse.
+:- import_module transform_hlds.ctgc.structure_reuse.analysis.
 :- import_module transform_hlds.exception_analysis.
 :- import_module transform_hlds.tabling_analysis.
 :- import_module transform_hlds.trailing_analysis.
@@ -96,6 +98,11 @@
             unit1 : unit(structure_sharing_call),
             unit1 : unit(structure_sharing_answer)),
 
+    analyses(mmc, "structure_reuse") =
+        'new analysis_type'(
+            unit1 : unit(structure_reuse_call),
+            unit1 : unit(structure_reuse_answer)),
+
     module_name_to_read_file_name(mmc, ModuleName, Ext, FileName, !IO) :-
         mmc_module_name_to_read_file_name(ModuleName, Ext, FileName, !IO),
 
Index: compiler/structure_reuse.analysis.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/structure_reuse.analysis.m,v
retrieving revision 1.11
diff -u -r1.11 structure_reuse.analysis.m
--- compiler/structure_reuse.analysis.m	17 Apr 2008 04:21:51 -0000	1.11
+++ compiler/structure_reuse.analysis.m	7 May 2008 05:04:51 -0000
@@ -50,6 +50,7 @@
 :- module transform_hlds.ctgc.structure_reuse.analysis.
 :- interface.
 
+:- import_module analysis.
 :- import_module hlds.hlds_module.
 :- import_module hlds.hlds_pred.
 
@@ -70,20 +71,38 @@
     io::di, io::uo) is det.
 
 %-----------------------------------------------------------------------------%
+
+:- type structure_reuse_call.
+:- type structure_reuse_answer.
+:- type structure_reuse_func_info.
+
+:- instance analysis(structure_reuse_func_info, structure_reuse_call,   
+    structure_reuse_answer).
+
+:- instance call_pattern(structure_reuse_func_info, structure_reuse_call).
+:- instance partial_order(structure_reuse_func_info, structure_reuse_call).
+:- instance to_string(structure_reuse_call).
+
+:- instance answer_pattern(structure_reuse_func_info, structure_reuse_answer).
+:- instance partial_order(structure_reuse_func_info, structure_reuse_answer).
+:- instance to_string(structure_reuse_answer).
+
+%-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
 :- implementation.
 
 :- import_module check_hlds.goal_path.
 :- import_module hlds.passes_aux.
+:- import_module libs.compiler_util.
 :- import_module libs.globals.
 :- import_module libs.options.
 :- import_module mdbcomp.prim_data.
 :- import_module parse_tree.error_util.
 :- import_module parse_tree.mercury_to_mercury.
 :- import_module parse_tree.modules.
-:- import_module parse_tree.prog_data.
 :- import_module parse_tree.prog_ctgc.
+:- import_module parse_tree.prog_data.
 :- import_module parse_tree.prog_out.
 :- import_module parse_tree.prog_type.
 :- import_module transform_hlds.ctgc.structure_reuse.direct.
@@ -93,6 +112,7 @@
 :- import_module transform_hlds.ctgc.structure_reuse.lfu.
 :- import_module transform_hlds.ctgc.structure_reuse.versions.
 :- import_module transform_hlds.ctgc.structure_sharing.domain.
+:- import_module transform_hlds.mmc_analysis.
 
 :- import_module bool.
 :- import_module list.
@@ -100,6 +120,7 @@
 :- import_module maybe.
 :- import_module pair.
 :- import_module set.
+:- import_module string.
 :- import_module svmap.
 
 %-----------------------------------------------------------------------------%
@@ -108,7 +129,14 @@
     globals.io_lookup_bool_option(very_verbose, VeryVerbose, !IO),
 
     % Process all imported reuse information.
-    process_imported_reuse(!ModuleInfo), 
+    globals.io_lookup_bool_option(intermodule_analysis, IntermodAnalysis, !IO),
+    (
+        IntermodAnalysis = yes,
+        process_intermod_analysis_imported_reuse(!ModuleInfo)
+    ;
+        IntermodAnalysis = no,
+        process_imported_reuse(!ModuleInfo)
+    ),
 
     % Load all available structure sharing information into a sharing table.
     SharingTable = load_structure_sharing_table(!.ModuleInfo),
@@ -128,15 +156,14 @@
 
     % Determine information about possible direct reuses.
     maybe_write_string(VeryVerbose, "% Direct reuse...\n", !IO), 
-    direct_reuse_pass(SharingTable, !ModuleInfo, 
-        ReuseTable0, ReuseTable1, !IO),
+    direct_reuse_pass(SharingTable, !ModuleInfo, ReuseTable0, ReuseTable1, !IO),
     maybe_write_string(VeryVerbose, "% Direct reuse: done.\n", !IO),
     reuse_as_table_maybe_dump(VeryVerbose, !.ModuleInfo, ReuseTable1, !IO),
 
     % Determine information about possible indirect reuses.
     maybe_write_string(VeryVerbose, "% Indirect reuse...\n", !IO), 
     indirect_reuse_pass(SharingTable, !ModuleInfo, ReuseTable1, ReuseTable2, 
-       !IO), 
+       DepProcs, !IO), 
     maybe_write_string(VeryVerbose, "% Indirect reuse: done.\n", !IO),
     reuse_as_table_maybe_dump(VeryVerbose, !.ModuleInfo, ReuseTable2, !IO),
 
@@ -161,7 +188,6 @@
     % `--intermodule-optimization' not `--intermodule-analysis'.
     globals.io_lookup_bool_option(make_optimization_interface, MakeOptInt,
         !IO),
-    globals.io_lookup_bool_option(intermodule_analysis, IntermodAnalysis, !IO),
     (
         MakeOptInt = yes,
         IntermodAnalysis = no
@@ -169,6 +195,24 @@
         make_opt_int(!ModuleInfo, !IO)
     ;
         true
+    ),
+
+    % If making a `.analysis' file, record structure sharing results, analysis
+    % dependencies, assumed answers and requests in the analysis framework.
+    globals.io_lookup_bool_option(make_analysis_registry, MakeAnalysisRegistry,
+        !IO),
+    (
+        MakeAnalysisRegistry = yes,
+        some [!AnalysisInfo] (
+            module_info_get_analysis_info(!.ModuleInfo, !:AnalysisInfo),
+            map.foldl(record_structure_reuse_results(!.ModuleInfo),
+                ReuseTable2, !AnalysisInfo),
+            list.foldl(handle_dep_procs(!.ModuleInfo), DepProcs,
+                !AnalysisInfo),
+            module_info_set_analysis_info(!.AnalysisInfo, !ModuleInfo)
+        )
+    ;
+        MakeAnalysisRegistry = no
     ).
 
     % Output some profiling information.
@@ -186,17 +230,18 @@
         InitialReuseTable, !ModuleInfo).
 
 :- pred create_forwarding_procedures_2(reuse_as_table::in, pred_proc_id::in,
-    reuse_as::in, module_info::in, module_info::out) is det.
+    reuse_as_and_status::in, module_info::in, module_info::out) is det.
 
-create_forwarding_procedures_2(FinalReuseTable, PPId, InitialReuseAs,
-        !ModuleInfo) :-
+create_forwarding_procedures_2(FinalReuseTable, PPId,
+        reuse_as_and_status(InitialReuseAs, _), !ModuleInfo) :-
     PPId = proc(PredId, _),
     module_info_pred_info(!.ModuleInfo, PredId, PredInfo),
     pred_info_get_import_status(PredInfo, ImportStatus),
     (
         reuse_as_conditional_reuses(InitialReuseAs),
         status_defined_in_this_module(ImportStatus) = yes,
-        map.search(FinalReuseTable, PPId, FinalReuseAs),
+        map.search(FinalReuseTable, PPId, FinalReuseAs_Status),
+        FinalReuseAs_Status = reuse_as_and_status(FinalReuseAs, _),
         reuse_as_no_reuses(FinalReuseAs)
     ->
         create_fake_reuse_procedure(PPId, !ModuleInfo)
@@ -264,7 +309,10 @@
                 rename_structure_reuse_domain(VarRenaming, !.TypeSubst,
                     ImpReuse, Reuse)
             ),
-            proc_info_set_structure_reuse(Reuse, !ProcInfo), 
+            % Optimality does not apply to `--intermodule-optimisation'
+            % system, only `--intermodule-analysis'.
+            proc_info_set_structure_reuse(
+                structure_reuse_domain_and_status(Reuse, optimal), !ProcInfo), 
             proc_info_reset_imported_structure_reuse(!ProcInfo),
             svmap.det_update(ProcId, !.ProcInfo, !ProcTable)
         ;
@@ -274,26 +322,131 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred save_reuse_in_module_info(pred_proc_id::in, reuse_as::in,
+    % Process the intermodule imported sharing information from the analysis
+    % framework
+    %
+:- pred process_intermod_analysis_imported_reuse(module_info::in,
+    module_info::out) is det.
+
+process_intermod_analysis_imported_reuse(!ModuleInfo):-
+    module_info_predids(PredIds, !ModuleInfo), 
+    list.foldl(process_intermod_analysis_imported_reuse_in_pred, PredIds,
+        !ModuleInfo).
+
+:- pred process_intermod_analysis_imported_reuse_in_pred(pred_id::in,
+    module_info::in, module_info::out) is det.
+
+process_intermod_analysis_imported_reuse_in_pred(PredId, !ModuleInfo) :- 
+    some [!PredTable] (
+        module_info_preds(!.ModuleInfo, !:PredTable), 
+        PredInfo0 = !.PredTable ^ det_elem(PredId), 
+        pred_info_get_import_status(PredInfo0, ImportStatus),
+        ( ImportStatus = status_imported(_) ->
+            module_info_get_analysis_info(!.ModuleInfo, AnalysisInfo),
+            process_intermod_analysis_imported_reuse_in_procs(!.ModuleInfo,
+                AnalysisInfo, PredId, PredInfo0, PredInfo),
+            svmap.det_update(PredId, PredInfo, !PredTable),
+            module_info_set_preds(!.PredTable, !ModuleInfo)
+        ;
+            true
+        )
+    ).
+
+:- pred process_intermod_analysis_imported_reuse_in_procs(module_info::in,
+    analysis_info::in, pred_id::in, pred_info::in, pred_info::out) is det.
+
+process_intermod_analysis_imported_reuse_in_procs(ModuleInfo, AnalysisInfo,
+        PredId, !PredInfo) :- 
+    some [!ProcTable] (
+        pred_info_get_procedures(!.PredInfo, !:ProcTable), 
+        ProcIds = pred_info_procids(!.PredInfo), 
+        list.foldl(
+            process_intermod_analysis_imported_reuse_in_proc(ModuleInfo,
+                AnalysisInfo, PredId, !.PredInfo), 
+            ProcIds, !ProcTable),
+        pred_info_set_procedures(!.ProcTable, !PredInfo)
+    ).
+
+:- pred process_intermod_analysis_imported_reuse_in_proc(module_info::in,
+    analysis_info::in, pred_id::in, pred_info::in, proc_id::in,
+    proc_table::in, proc_table::out) is det.
+
+process_intermod_analysis_imported_reuse_in_proc(ModuleInfo, AnalysisInfo,
+        PredId, PredInfo, ProcId, !ProcTable) :- 
+    PPId = proc(PredId, ProcId),
+    some [!ProcInfo] (
+        !:ProcInfo = !.ProcTable ^ det_elem(ProcId), 
+
+        module_name_func_id(ModuleInfo, PPId, ModuleName, FuncId),
+        FuncInfo = structure_reuse_func_info(ModuleInfo, !.ProcInfo),
+        lookup_best_result(AnalysisInfo, ModuleName, FuncId, FuncInfo,
+            structure_reuse_call, MaybeBestResult),
+        (
+            MaybeBestResult = yes(analysis_result(_Call, Answer,
+                ResultStatus)),
+            structure_reuse_answer_to_domain(PredInfo, !.ProcInfo, Answer,
+                Reuse),
+            proc_info_set_structure_reuse(
+                structure_reuse_domain_and_status(Reuse, ResultStatus),
+                !ProcInfo),
+            svmap.det_update(ProcId, !.ProcInfo, !ProcTable)
+        ;
+            MaybeBestResult = no
+        )
+    ).
+
+:- pred structure_reuse_answer_to_domain(pred_info::in,
+    proc_info::in, structure_reuse_answer::in, structure_reuse_domain::out)
+    is det.
+
+structure_reuse_answer_to_domain(PredInfo, ProcInfo, Answer, Reuse) :-
+    (
+        Answer = structure_reuse_answer_no_reuse,
+        Reuse = has_no_reuse
+    ;
+        Answer = structure_reuse_answer_unconditional,
+        Reuse = has_only_unconditional_reuse
+    ;
+        Answer = structure_reuse_answer_conditional(ImpHeadVars, ImpTypes,
+            ImpReuseAs),
+        proc_info_get_headvars(ProcInfo, HeadVars),
+        pred_info_get_arg_types(PredInfo, HeadVarTypes),
+        map.from_corresponding_lists(ImpHeadVars, HeadVars, VarRenaming),
+        ( type_unify_list(ImpTypes, HeadVarTypes, [], map.init, TypeSubst) ->
+            ImpReuseDomain = to_structure_reuse_domain(ImpReuseAs),
+            rename_structure_reuse_domain(VarRenaming, TypeSubst,
+                ImpReuseDomain, Reuse)
+        ;
+            unexpected(this_file,
+                "structure_reuse_answer_to_domain: type_unify_list failed")
+        )
+    ).
+
+%-----------------------------------------------------------------------------%
+
+:- pred save_reuse_in_module_info(pred_proc_id::in, reuse_as_and_status::in,
     module_info::in, module_info::out) is det.
 
-save_reuse_in_module_info(PPId, ReuseAs, !ModuleInfo) :- 
-    save_reuse_in_module_info_2(PPId, ReuseAs, !ModuleInfo), 
+save_reuse_in_module_info(PPId, ReuseAs_Status, !ModuleInfo) :- 
+    save_reuse_in_module_info_2(PPId, ReuseAs_Status, !ModuleInfo), 
     module_info_get_structure_reuse_map(!.ModuleInfo, ReuseMap), 
     ( map.search(ReuseMap, PPId, Result) -> 
         Result = ReusePPId - _Name, 
-        save_reuse_in_module_info_2(ReusePPId, ReuseAs, !ModuleInfo)
+        save_reuse_in_module_info_2(ReusePPId, ReuseAs_Status, !ModuleInfo)
     ;
         true
     ).
 
-:- pred save_reuse_in_module_info_2(pred_proc_id::in, reuse_as::in,
+:- pred save_reuse_in_module_info_2(pred_proc_id::in, reuse_as_and_status::in,
     module_info::in, module_info::out) is det.
 
-save_reuse_in_module_info_2(PPId, ReuseAs, !ModuleInfo) :- 
+save_reuse_in_module_info_2(PPId, ReuseAs_Status, !ModuleInfo) :- 
+    ReuseAs_Status = reuse_as_and_status(ReuseAs, Status),
+    ReuseDomain = to_structure_reuse_domain(ReuseAs),
+    Domain_Status = structure_reuse_domain_and_status(ReuseDomain, Status),
+
     module_info_pred_proc_info(!.ModuleInfo, PPId, PredInfo, ProcInfo0),
-    proc_info_set_structure_reuse(to_structure_reuse_domain(ReuseAs),
-        ProcInfo0, ProcInfo),
+    proc_info_set_structure_reuse(Domain_Status, ProcInfo0, ProcInfo),
     module_info_set_pred_proc_info(PPId, PredInfo, ProcInfo, !ModuleInfo).
 
 :- pred annotate_in_use_information(pred_id::in, proc_id::in,
@@ -345,65 +498,311 @@
 
 write_pred_reuse_info(ModuleInfo, PredId, !IO) :-
     module_info_pred_info(ModuleInfo, PredId, PredInfo),
-    pred_info_get_import_status(PredInfo, ImportStatus),
-    pred_info_get_origin(PredInfo, PredOrigin),
-    module_info_get_type_spec_info(ModuleInfo, TypeSpecInfo),
-    TypeSpecInfo = type_spec_info(_, TypeSpecForcePreds, _, _),
+    PredName = pred_info_name(PredInfo),
+    ProcIds = pred_info_procids(PredInfo),
+    PredOrFunc = pred_info_is_pred_or_func(PredInfo),
+    ModuleName = pred_info_module(PredInfo),
+    pred_info_get_procedures(PredInfo, ProcTable),
+    pred_info_get_context(PredInfo, Context),
+    SymName = qualified(ModuleName, PredName),
+    pred_info_get_typevarset(PredInfo, TypeVarSet),
+    list.foldl(write_proc_reuse_info(ModuleInfo, PredId, PredInfo, ProcTable,
+        PredOrFunc, SymName, Context, TypeVarSet), ProcIds, !IO).
+
+:- pred write_proc_reuse_info(module_info::in, pred_id::in, pred_info::in,
+    proc_table::in, pred_or_func::in, sym_name::in, prog_context::in,
+    tvarset::in, proc_id::in, io::di, io::uo) is det.
+
+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),
     (
+        ShouldWrite = yes,
+        map.lookup(ProcTable, ProcId, ProcInfo),
+        proc_info_get_structure_reuse(ProcInfo, MaybeStructureReuseDomain),
+        proc_info_declared_argmodes(ProcInfo, Modes),
+        proc_info_get_varset(ProcInfo, VarSet),
+        proc_info_get_headvars(ProcInfo, HeadVars),
+        proc_info_get_vartypes(ProcInfo, VarTypes),
+        list.map(map.lookup(VarTypes), HeadVars, HeadVarTypes),
         (
-            ImportStatus = status_exported
+            MaybeStructureReuseDomain = yes(
+                structure_reuse_domain_and_status(Reuse, _Status)),
+            MaybeReuse = yes(Reuse)
         ;
-            ImportStatus = status_opt_exported
+            MaybeStructureReuseDomain = no,
+            MaybeReuse = no
+        ),
+        write_pragma_structure_reuse_info(PredOrFunc, SymName, Modes,
+            Context, HeadVars, yes(VarSet), HeadVarTypes, yes(TypeVarSet),
+            MaybeReuse, !IO)
+    ;
+        ShouldWrite = no
+    ).
+
+%-----------------------------------------------------------------------------%
+%
+% Types and instances for the intermodule analysis framework
+%
+
+:- type structure_reuse_call
+    --->    structure_reuse_call.
+            % Eventually we should have different call patterns.
+
+:- type structure_reuse_answer
+    --->    structure_reuse_answer_no_reuse
+    ;       structure_reuse_answer_unconditional
+    ;       structure_reuse_answer_conditional(
+                prog_vars,
+                list(mer_type),
+                reuse_as
+            ).
+
+:- type structure_reuse_func_info
+    --->    structure_reuse_func_info(
+                module_info,
+                proc_info
+            ).
+
+:- func analysis_name = string.
+
+analysis_name = "structure_reuse".
+
+:- instance analysis(structure_reuse_func_info, structure_reuse_call,
+    structure_reuse_answer) where
+[
+    analysis_name(_, _) = analysis_name,
+    analysis_version_number(_, _) = 1,
+    preferred_fixpoint_type(_, _) = greatest_fixpoint,
+    bottom(_, _) = structure_reuse_answer_no_reuse,
+    ( top(_, _) = _ :-
+        % We have no representation for "all possible conditions".
+        unexpected(this_file, "top/2 called")
+    ),
+    ( get_func_info(ModuleInfo, ModuleName, FuncId, _, _, FuncInfo) :-
+        func_id_to_ppid(ModuleInfo, ModuleName, FuncId, PPId),
+        module_info_proc_info(ModuleInfo, PPId, ProcInfo),
+        FuncInfo = structure_reuse_func_info(ModuleInfo, ProcInfo)
+    )
+].
+
+:- instance call_pattern(structure_reuse_func_info, structure_reuse_call)
+    where [].
+
+:- instance partial_order(structure_reuse_func_info, structure_reuse_call)
+        where [
+    (more_precise_than(_, _, _) :-
+        semidet_fail
+    ),
+    equivalent(_, Call, Call)
+].
+
+:- instance to_string(structure_reuse_call) where [
+    to_string(structure_reuse_call) = "",
+    from_string("") = structure_reuse_call
+].
+
+:- instance answer_pattern(structure_reuse_func_info, structure_reuse_answer)
+    where [].
+
+:- instance partial_order(structure_reuse_func_info, structure_reuse_answer)
+        where [
+
+    % We deliberately have `conditional' reuse incomparable with
+    % `unconditional' reuse.  If they were comparable, a caller using an
+    % `conditional' answer would would only be marked `suboptimal' if that
+    % answer changes to `unconditional'.  Since we don't honour the old
+    % `conditional' answer by generating that version of the procedure, there
+    % would be a linking error if the caller is not updated to call the
+    % unconditional version.
+
+    (more_precise_than(FuncInfo, Answer1, Answer2) :-
+        (
+            Answer1 = structure_reuse_answer_conditional(_, _, _),
+            Answer2 = structure_reuse_answer_no_reuse
+        ;
+            Answer1 = structure_reuse_answer_unconditional,
+            Answer2 = structure_reuse_answer_no_reuse
+        ;
+            Answer1 = structure_reuse_answer_conditional(_, _, ReuseAs1),
+            Answer2 = structure_reuse_answer_conditional(_, _, ReuseAs2),
+            % XXX can we implement this more efficiently?
+            FuncInfo = structure_reuse_func_info(ModuleInfo, ProcInfo),
+            reuse_as_subsumed_by(ModuleInfo, ProcInfo, ReuseAs1, ReuseAs2),
+            not reuse_as_subsumed_by(ModuleInfo, ProcInfo, ReuseAs2, ReuseAs1)
+        )
+    ),
+
+    (equivalent(FuncInfo, Answer1, Answer2) :-
+        (
+            Answer1 = Answer2
+        ;
+            Answer1 = structure_reuse_answer_conditional(_, _, ReuseAs1),
+            Answer2 = structure_reuse_answer_conditional(_, _, ReuseAs2),
+            % XXX can we implement this more efficiently?
+            FuncInfo = structure_reuse_func_info(ModuleInfo, ProcInfo),
+            reuse_as_subsumed_by(ModuleInfo, ProcInfo, ReuseAs2, ReuseAs1),
+            reuse_as_subsumed_by(ModuleInfo, ProcInfo, ReuseAs1, ReuseAs2)
+        )
+    )
+].
+
+:- instance to_string(structure_reuse_answer) where [
+    func(to_string/1) is reuse_answer_to_string,
+    func(from_string/1) is reuse_answer_from_string
+].
+
+:- func reuse_answer_to_string(structure_reuse_answer) = string.
+
+reuse_answer_to_string(Answer) = String :-
+    (
+        Answer = structure_reuse_answer_no_reuse,
+        String = "no_reuse"
+    ;
+        Answer = structure_reuse_answer_unconditional,
+        String = "uncond"
+    ;
+        Answer = structure_reuse_answer_conditional(HeadVars, Types, ReuseAs),
+        ReuseDomain = to_structure_reuse_domain(ReuseAs),
+        String = string({HeadVars, Types, ReuseDomain})
+    ).
+
+:- func reuse_answer_from_string(string::in) =
+    (structure_reuse_answer::out) is det.
+
+reuse_answer_from_string(String) = Answer :-
+    ( String = "no_reuse" ->
+        Answer = structure_reuse_answer_no_reuse
+    ; String = "uncond" ->
+        Answer = structure_reuse_answer_unconditional
+    ;
+        % XXX this is ugly.  Later we should move to writing call and answer
+        % patterns in analysis files as terms rather than strings which will
+        % clean this up.
+        StringStop = String ++ ".",
+        io.read_from_string("", StringStop, string.length(StringStop), Res,
+            posn(0, 0, 0), _Posn),
+        (
+            Res = ok({HeadVars, Types, ReuseDomain}),
+            ReuseAs = from_structure_reuse_domain(ReuseDomain),
+            Answer = structure_reuse_answer_conditional(HeadVars, Types,
+                ReuseAs)
         ;
-            ImportStatus = status_exported_to_submodules
+            ( Res = eof
+            ; Res = error(_, _)
+            ),
+            unexpected(this_file, "reuse_answer_from_string: " ++ String)
+        )
+    ).
+
+%-----------------------------------------------------------------------------%
+%
+% Additional predicates used for intermodule analysis
+%
+
+:- pred record_structure_reuse_results(module_info::in, pred_proc_id::in,
+    reuse_as_and_status::in, analysis_info::in, analysis_info::out) is det.
+
+record_structure_reuse_results(ModuleInfo, PPId, ReuseAs_Status,
+        !AnalysisInfo) :-
+    PPId = proc(PredId, ProcId),
+    ReuseAs_Status = reuse_as_and_status(ReuseAs, Status),
+
+    module_info_pred_info(ModuleInfo, PredId, PredInfo),
+    should_write_reuse_info(ModuleInfo, PredId, ProcId, PredInfo,
+        allow_type_spec_preds, ShouldWrite),
+    (
+        ShouldWrite = yes,
+        ( reuse_as_no_reuses(ReuseAs) ->
+            Answer = structure_reuse_answer_no_reuse
+        ; reuse_as_all_unconditional_reuses(ReuseAs) ->
+            Answer = structure_reuse_answer_unconditional
+        ; reuse_as_conditional_reuses(ReuseAs) ->
+            module_info_pred_proc_info(ModuleInfo, PPId, _PredInfo, ProcInfo),
+            proc_info_get_headvars(ProcInfo, HeadVars),
+            proc_info_get_vartypes(ProcInfo, VarTypes),
+            map.apply_to_list(HeadVars, VarTypes, HeadVarTypes),
+            Answer = structure_reuse_answer_conditional(HeadVars, HeadVarTypes,
+                ReuseAs)
+        ;
+            unexpected(this_file, "record_structure_reuse_results")
         ),
-        \+ is_unify_or_compare_pred(PredInfo),
+        module_name_func_id(ModuleInfo, PPId, ModuleName, FuncId),
+        record_result(ModuleName, FuncId, structure_reuse_call, Answer, Status,
+            !AnalysisInfo)
+    ;
+        ShouldWrite = no
+    ).
 
-        % Don't write out info for reuse versions of procedures.
-        PredOrigin \= origin_transformed(transform_structure_reuse, _, _),
+:- pred handle_dep_procs(module_info::in, pred_proc_id::in,
+    analysis_info::in, analysis_info::out) is det.
 
-        % 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 error.
-        \+ set.member(PredId, TypeSpecForcePreds)
-    ->
-        PredName = pred_info_name(PredInfo),
-        ProcIds = pred_info_procids(PredInfo),
-        PredOrFunc = pred_info_is_pred_or_func(PredInfo),
-        ModuleName = pred_info_module(PredInfo),
-        pred_info_get_procedures(PredInfo, ProcTable),
-        pred_info_get_context(PredInfo, Context),
-        SymName = qualified(ModuleName, PredName),
-        pred_info_get_typevarset(PredInfo, TypeVarSet),
-        list.foldl(write_proc_reuse_info(ProcTable, PredOrFunc, SymName, 
-            Context, TypeVarSet), ProcIds, !IO)
+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_reuse_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 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,
+        record_result(DepModuleName, DepFuncId, Call, Answer, suboptimal,
+            !AnalysisInfo),
+        % Record a request as well.
+        record_request(analysis_name, DepModuleName, DepFuncId, Call,
+            !AnalysisInfo)
     ;
-        true
+        AnyResults = [_ | _]
     ).
 
-:- pred write_proc_reuse_info(proc_table::in, pred_or_func::in, 
-    sym_name::in, prog_context::in, tvarset::in, proc_id::in, 
-    io::di, io::uo) is det.
+%-----------------------------------------------------------------------------%
 
-write_proc_reuse_info(ProcTable, PredOrFunc, SymName, 
-        Context, TypeVarSet, ProcId, !IO) :-
-    globals.io_lookup_bool_option(structure_reuse_analysis,
-        ReuseAnalysis, !IO),
+:- type allow_type_spec_preds
+    --->    allow_type_spec_preds
+    ;       disallow_type_spec_preds.
+
+:- 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.
+
+should_write_reuse_info(ModuleInfo, PredId, ProcId, PredInfo,
+        AllowTypeSpecPreds, ShouldWrite) :-
     (
-        ReuseAnalysis = yes,
-        map.lookup(ProcTable, ProcId, ProcInfo),
-        proc_info_get_structure_reuse(ProcInfo, MaybeStructureReuseDomain),
-        proc_info_declared_argmodes(ProcInfo, Modes),
-        proc_info_get_varset(ProcInfo, VarSet),
-        proc_info_get_headvars(ProcInfo, HeadVars),
-        proc_info_get_vartypes(ProcInfo, VarTypes),
-        list.map(map.lookup(VarTypes), HeadVars, HeadVarTypes),
-        write_pragma_structure_reuse_info(PredOrFunc, SymName, Modes,
-            Context, HeadVars, yes(VarSet), HeadVarTypes, yes(TypeVarSet),
-            MaybeStructureReuseDomain, !IO)
+        procedure_is_exported(ModuleInfo, PredInfo, ProcId),
+        \+ is_unify_or_compare_pred(PredInfo),
+
+        % Don't write out info for reuse versions of procedures.
+        pred_info_get_origin(PredInfo, PredOrigin),
+        PredOrigin \= origin_transformed(transform_structure_reuse, _, _),
+
+        (
+            AllowTypeSpecPreds = allow_type_spec_preds
+        ;
+            AllowTypeSpecPreds = disallow_type_spec_preds,
+            % 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
+            % error.
+            module_info_get_type_spec_info(ModuleInfo, TypeSpecInfo),
+            TypeSpecInfo = type_spec_info(_, TypeSpecForcePreds, _, _),
+            \+ set.member(PredId, TypeSpecForcePreds)
+        )
+    ->
+        ShouldWrite = yes
     ;
-        ReuseAnalysis = no
+        ShouldWrite = no
     ).
+
 %-----------------------------------------------------------------------------%
 
 :- func this_file = string.
Index: compiler/structure_reuse.direct.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/structure_reuse.direct.m,v
retrieving revision 1.10
diff -u -r1.10 structure_reuse.direct.m
--- compiler/structure_reuse.direct.m	27 Mar 2008 02:29:42 -0000	1.10
+++ compiler/structure_reuse.direct.m	7 May 2008 05:04:51 -0000
@@ -42,6 +42,7 @@
 
 :- implementation. 
 
+:- import_module analysis.
 :- import_module hlds.hlds_goal.
 :- import_module hlds.hlds_pred.
 :- import_module hlds.passes_aux.
@@ -126,11 +127,28 @@
         % We can't analyse compiler generated special predicates.
         true
     ;
+        pred_info_get_import_status(PredInfo0, status_external(_))
+    ->
+        % We can't analyse `:- external' predicates but add an extry to the
+        % reuse table so something will be written out to optimisation
+        % interface files.
+        list.foldl(
+            set_external_pred_reuse_as(PredId, reuse_as_init, optimal),
+            pred_info_procids(PredInfo0), !ReuseTable)
+    ;
         list.foldl3(direct_reuse_process_proc(Strategy, SharingTable, PredId), 
             pred_info_non_imported_procids(PredInfo0), !ModuleInfo, 
             !ReuseTable, !IO)
     ).
 
+:- pred set_external_pred_reuse_as(pred_id::in, reuse_as::in,
+    analysis_status::in, proc_id::in, reuse_as_table::in, reuse_as_table::out)
+    is det.
+
+set_external_pred_reuse_as(PredId, ReuseAs, Status, ProcId, !ReuseTable) :-
+    reuse_as_table_set(proc(PredId, ProcId),
+        reuse_as_and_status(ReuseAs, Status), !ReuseTable).
+
 :- pred direct_reuse_process_proc(reuse_strategy::in, sharing_as_table::in, 
     pred_id::in, proc_id::in, module_info::in, module_info::out,
     reuse_as_table::in, reuse_as_table::out, io::di, io::uo) is det.
@@ -144,7 +162,10 @@
 
     direct_reuse_process_procedure(Strategy, SharingTable, PredId, ProcId, 
         !.ModuleInfo, Pred0, Proc0, Proc, ReuseAs, !IO), 
-    reuse_as_table_set(proc(PredId, ProcId), ReuseAs, !ReuseTable),
+    % XXX is this right?
+    Status = optimal,
+    reuse_as_table_set(proc(PredId, ProcId),
+        reuse_as_and_status(ReuseAs, Status), !ReuseTable),
 
     map.det_update(Procs0, ProcId, Proc, Procs),
     pred_info_set_procedures(Procs, Pred0, Pred),
Index: compiler/structure_reuse.domain.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/structure_reuse.domain.m,v
retrieving revision 1.14
diff -u -r1.14 structure_reuse.domain.m
--- compiler/structure_reuse.domain.m	28 Apr 2008 07:23:12 -0000	1.14
+++ compiler/structure_reuse.domain.m	7 May 2008 05:04:51 -0000
@@ -17,6 +17,7 @@
 :- module transform_hlds.ctgc.structure_reuse.domain.
 :- interface.
 
+:- import_module analysis.
 :- import_module hlds.hlds_module.
 :- import_module hlds.hlds_pred.
 :- import_module parse_tree.prog_data.
@@ -100,6 +101,9 @@
 :- pred reuse_as_subsumed_by(module_info::in, proc_info::in, reuse_as::in, 
     reuse_as::in) is semidet.
 
+:- pred reuse_as_and_status_subsumed_by(module_info::in, proc_info::in,
+    reuse_as_and_status::in, reuse_as_and_status::in) is semidet.
+
     % Tests to see whether the reuses description describes no reuses at all, 
     % only unconditional reuses, or conditional reuses resp.
     %
@@ -205,12 +209,20 @@
 
     % Intermediate storage of the reuse results for individual procedures.
     %
-:- type reuse_as_table == map(pred_proc_id, reuse_as).
+:- type reuse_as_table == map(pred_proc_id, reuse_as_and_status).
+
+:- type reuse_as_and_status
+    --->    reuse_as_and_status(
+                reuse_as,
+                analysis_status
+            ).
 
 :- func reuse_as_table_init = reuse_as_table.
-:- func reuse_as_table_search(pred_proc_id, reuse_as_table) 
-    = reuse_as is semidet.
-:- pred reuse_as_table_set(pred_proc_id::in, reuse_as::in, 
+
+:- pred reuse_as_table_search(pred_proc_id::in, reuse_as_table::in, 
+    reuse_as_and_status::out) is semidet.
+
+:- pred reuse_as_table_set(pred_proc_id::in, reuse_as_and_status::in, 
     reuse_as_table::in, reuse_as_table::out) is det.
 
 :- pred reuse_as_table_maybe_dump(bool::in, module_info::in,
@@ -412,6 +424,13 @@
         NotSubsumed = []
     ).
 
+reuse_as_and_status_subsumed_by(ModuleInfo, ProcInfo,
+        ReuseAs_Status1, ReuseAs_Status2) :-
+    ReuseAs_Status1 = reuse_as_and_status(Reuse1, _Status1),
+    ReuseAs_Status2 = reuse_as_and_status(Reuse2, _Status2),
+    reuse_as_subsumed_by(ModuleInfo, ProcInfo, Reuse1, Reuse2).
+    % XXX do we need to compare Status1 and Status2?
+
 reuse_as_no_reuses(no_reuse).
 reuse_as_all_unconditional_reuses(unconditional).
 reuse_as_conditional_reuses(conditional(_)).
@@ -818,9 +837,12 @@
 %
 
 reuse_as_table_init = map.init.
-reuse_as_table_search(PPId, Table) = Table ^ elem(PPId). 
-reuse_as_table_set(PPId, ReuseAs, !Table) :- 
-    !:Table = !.Table ^ elem(PPId) := ReuseAs.
+
+reuse_as_table_search(PPId, Table, ReuseAs_Status) :-
+    map.search(Table, PPId, ReuseAs_Status).
+
+reuse_as_table_set(PPId, ReuseAs_Status, !Table) :- 
+    !Table ^ elem(PPId) := ReuseAs_Status.
 
 reuse_as_table_maybe_dump(DoDump, ModuleInfo, Table, !IO) :-
     (
@@ -841,10 +863,10 @@
         map.foldl(dump_entries(ModuleInfo), Table, !IO)
     ).
 
-:- pred dump_entries(module_info::in, pred_proc_id::in, reuse_as::in,
-    io::di, io::uo) is det.
+:- pred dump_entries(module_info::in, pred_proc_id::in,
+    reuse_as_and_status::in, io::di, io::uo) is det.
 
-dump_entries(ModuleInfo, PPId, ReuseAs, !IO) :-
+dump_entries(ModuleInfo, PPId, reuse_as_and_status(ReuseAs, _Status), !IO) :-
     io.write_string("% ", !IO),
     write_pred_proc_id(ModuleInfo, PPId, !IO),
     io.write_string("\t--> ", !IO),
@@ -872,10 +894,12 @@
     module_info_proc_info(ModuleInfo, PredId, ProcId, ProcInfo),
     proc_info_get_structure_reuse(ProcInfo, MaybePublicReuse),
     (
-        MaybePublicReuse = yes(PublicReuse),
+        MaybePublicReuse = yes(
+            structure_reuse_domain_and_status(PublicReuse, Status)),
         PPId = proc(PredId, ProcId),
         PrivateReuse = from_structure_reuse_domain(PublicReuse),
-        reuse_as_table_set(PPId, PrivateReuse, !ReuseTable)
+        reuse_as_table_set(PPId, reuse_as_and_status(PrivateReuse, Status), 
+            !ReuseTable)
     ;
         MaybePublicReuse = no
     ).
Index: compiler/structure_reuse.indirect.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/structure_reuse.indirect.m,v
retrieving revision 1.22
diff -u -r1.22 structure_reuse.indirect.m
--- compiler/structure_reuse.indirect.m	28 Apr 2008 07:23:12 -0000	1.22
+++ compiler/structure_reuse.indirect.m	7 May 2008 05:04:51 -0000
@@ -17,10 +17,12 @@
 :- interface.
 
 :- import_module hlds.hlds_module.
+:- import_module hlds.hlds_pred.
 :- import_module transform_hlds.ctgc.structure_reuse.domain.
 :- import_module transform_hlds.ctgc.structure_sharing.domain.
 
 :- import_module io.
+:- import_module list.
 
 %------------------------------------------------------------------------------%
 
@@ -41,7 +43,7 @@
     %
 :- pred indirect_reuse_pass(sharing_as_table::in, module_info::in,
     module_info::out, reuse_as_table::in, reuse_as_table::out,
-    io::di, io::uo) is det.
+    list(pred_proc_id)::out, io::di, io::uo) is det.
 
 %------------------------------------------------------------------------------%
 %------------------------------------------------------------------------------%
@@ -51,10 +53,10 @@
 :- import_module analysis.
 :- import_module hlds.hlds_goal.
 :- import_module hlds.hlds_out.
-:- import_module hlds.hlds_pred.
 :- import_module libs.compiler_util.
 :- import_module libs.globals.
 :- import_module libs.options.
+:- import_module mdbcomp.prim_data.
 :- import_module parse_tree.mercury_to_mercury.
 :- import_module parse_tree.prog_data.
 :- import_module parse_tree.prog_out.
@@ -67,7 +69,6 @@
 
 :- import_module bool.
 :- import_module int.
-:- import_module list.
 :- import_module map.
 :- import_module maybe.
 :- import_module pair.
@@ -76,7 +77,11 @@
 
 %------------------------------------------------------------------------------%
 
-indirect_reuse_pass(SharingTable, !ModuleInfo, !ReuseTable, !IO):-
+:- type dep_procs == list(pred_proc_id).
+
+%------------------------------------------------------------------------------%
+
+indirect_reuse_pass(SharingTable, !ModuleInfo, !ReuseTable, DepProcs, !IO):-
     %
     % Perform a bottom-up traversal of the SCCs in the module,
     % analysing indirect structure reuse in each one as we go.
@@ -87,7 +92,8 @@
         MaybeDepInfo = yes(DepInfo),
         hlds_dependency_info_get_dependency_ordering(DepInfo, SCCs),
         list.foldl3(indirect_reuse_analyse_scc(SharingTable), SCCs,
-            !ModuleInfo, !ReuseTable, !IO)
+            !ModuleInfo, !ReuseTable, [], DepProcs0),
+        DepProcs = list.sort_and_remove_dups(DepProcs0)
     ;
         MaybeDepInfo = no,
         unexpected(this_file, "No dependency information.")
@@ -95,43 +101,49 @@
 
 :- pred indirect_reuse_analyse_scc(sharing_as_table::in,
     list(pred_proc_id)::in, module_info::in, module_info::out,
-    reuse_as_table::in, reuse_as_table::out, io::di, io::uo) is det.
+    reuse_as_table::in, reuse_as_table::out, dep_procs::in, dep_procs::out)
+    is det.
 
-indirect_reuse_analyse_scc(SharingTable, SCC, !ModuleInfo, !ReuseTable, !IO) :-
+indirect_reuse_analyse_scc(SharingTable, SCC, !ModuleInfo, !ReuseTable,
+        !DepProcs) :-
     ( some_preds_requiring_no_analysis(!.ModuleInfo, SCC) ->
         true
     ;
+        FixpointTable0 = sr_fixpoint_table_init(!.ModuleInfo, SCC,
+            !.ReuseTable),
         indirect_reuse_analyse_scc_until_fixpoint(SharingTable,
-            SCC, !.ReuseTable, !ModuleInfo,
-            sr_fixpoint_table_init(SCC, !.ReuseTable), FixpointTable, !IO),
+            SCC, !.ReuseTable, !ModuleInfo, FixpointTable0, FixpointTable,
+            !DepProcs),
         list.foldl(update_reuse_in_table(FixpointTable), SCC, !ReuseTable)
     ).
 
 :- pred indirect_reuse_analyse_scc_until_fixpoint(sharing_as_table::in,
     list(pred_proc_id)::in, reuse_as_table::in,
     module_info::in, module_info::out,
-    sr_fixpoint_table::in, sr_fixpoint_table::out, io::di, io::uo) is det.
+    sr_fixpoint_table::in, sr_fixpoint_table::out,
+    dep_procs::in, dep_procs::out) is det.
 
 indirect_reuse_analyse_scc_until_fixpoint(SharingTable, SCC,
-        ReuseTable, !ModuleInfo, !FixpointTable, !IO):-
+        ReuseTable, !ModuleInfo, !FixpointTable, !DepProcs) :-
     list.foldl3(indirect_reuse_analyse_pred_proc(SharingTable, ReuseTable),
-        SCC, !ModuleInfo, !FixpointTable, !IO),
+        SCC, !ModuleInfo, !FixpointTable, !DepProcs),
     ( sr_fixpoint_table_stable(!.FixpointTable) ->
         true
     ;
         sr_fixpoint_table_new_run(!FixpointTable),
         indirect_reuse_analyse_scc_until_fixpoint(SharingTable,
-            SCC, ReuseTable, !ModuleInfo, !FixpointTable, !IO)
+            SCC, ReuseTable, !ModuleInfo, !FixpointTable, !DepProcs)
     ).
 
 %-----------------------------------------------------------------------------%
 
 :- pred indirect_reuse_analyse_pred_proc(sharing_as_table::in,
     reuse_as_table::in, pred_proc_id::in, module_info::in, module_info::out,
-    sr_fixpoint_table::in, sr_fixpoint_table::out, io::di, io::uo) is det.
+    sr_fixpoint_table::in, sr_fixpoint_table::out,
+    dep_procs::in, dep_procs::out) is det.
 
 indirect_reuse_analyse_pred_proc(SharingTable, ReuseTable, PPId,
-        !ModuleInfo, !FixpointTable, !IO):-
+        !ModuleInfo, !FixpointTable, !DepProcs) :-
     PPId = proc(PredId, _),
     module_info_pred_info(!.ModuleInfo, PredId, PredInfo),
     pred_info_get_origin(PredInfo, Origin),
@@ -140,17 +152,19 @@
         true
     ;
         indirect_reuse_analyse_pred_proc_2(SharingTable, ReuseTable, PPId,
-                !ModuleInfo, !FixpointTable, !IO)
+            !ModuleInfo, !FixpointTable, !DepProcs)
     ).
 
 :- pred indirect_reuse_analyse_pred_proc_2(sharing_as_table::in,
     reuse_as_table::in, pred_proc_id::in, module_info::in, module_info::out,
-    sr_fixpoint_table::in, sr_fixpoint_table::out, io::di, io::uo) is det.
+    sr_fixpoint_table::in, sr_fixpoint_table::out,
+    dep_procs::in, dep_procs::out) is det.
 
 indirect_reuse_analyse_pred_proc_2(SharingTable, ReuseTable, PPId,
-        !ModuleInfo, !FixpointTable, !IO):-
-    globals.io_lookup_bool_option(very_verbose, VeryVerbose, !IO),
-    globals.io_lookup_bool_option(debug_indirect_reuse, DebugIndirect, !IO),
+        !ModuleInfo, !FixpointTable, !DepProcs):-
+    module_info_get_globals(!.ModuleInfo, Globals),
+    globals.lookup_bool_option(Globals, very_verbose, VeryVerbose),
+    globals.lookup_bool_option(Globals, debug_indirect_reuse, DebugIndirect),
 
     PPId = proc(PredId, ProcId),
 
@@ -161,11 +175,13 @@
         ; DebugIndirect = yes
         )
     ->
-        io.write_string("% Indirect reuse analysis (run ", !IO),
-        io.write_int(Run, !IO),
-        io.write_string(") ", !IO),
-        hlds_out.write_pred_proc_id_pair(!.ModuleInfo, PredId, ProcId, !IO),
-        io.nl(!IO)
+        trace [io(!IO)] (
+            io.write_string("% Indirect reuse analysis (run ", !IO),
+            io.write_int(Run, !IO),
+            io.write_string(") ", !IO),
+            write_pred_proc_id_pair(!.ModuleInfo, PredId, ProcId, !IO),
+            io.nl(!IO)
+        )
     ;
         true
     ),
@@ -173,14 +189,14 @@
     % Some initialisation work...
     module_info_pred_proc_info(!.ModuleInfo, PPId, PredInfo0, ProcInfo0),
     proc_info_get_goal(ProcInfo0, Goal0),
-    BaseInfo = ir_background_info_init(!.ModuleInfo, PredInfo0, ProcInfo0,
-        SharingTable, ReuseTable),
-    AnalysisInfo0 = analysis_info_init(PPId, !.FixpointTable),
+    BaseInfo = ir_background_info_init(!.ModuleInfo, PPId, PredInfo0,
+        ProcInfo0, SharingTable, ReuseTable),
+    IrInfo0 = ir_analysis_info_init(PPId, !.FixpointTable),
 
     % The actual analysis of the goal:
-    indirect_reuse_analyse_goal(BaseInfo, Goal0, Goal, AnalysisInfo0,
-        AnalysisInfo),
-    !:FixpointTable = AnalysisInfo ^ fptable,
+    indirect_reuse_analyse_goal(BaseInfo, Goal0, Goal, IrInfo0, IrInfo,
+        !DepProcs),
+    !:FixpointTable = IrInfo ^ fptable,
 
     % Some feedback.
     (
@@ -188,18 +204,22 @@
         ; DebugIndirect = yes
         )
     ->
-        io.write_string("% FPT: ", !IO),
-        io.write_string(
-            sr_fixpoint_table_get_short_description(PPId, !.FixpointTable),
-            !IO),
-        io.nl(!IO)
+        trace [io(!IO)] (
+            io.write_string("% FPT: ", !IO),
+            io.write_string(
+                sr_fixpoint_table_get_short_description(PPId, !.FixpointTable),
+                !IO),
+            io.nl(!IO)
+        )
     ;
         true
     ),
 
     % Record the obtained reuse description in the fixpoint table...
-    sr_fixpoint_table_new_as(!.ModuleInfo, ProcInfo0, PPId,
-        AnalysisInfo ^ reuse_as, !FixpointTable),
+    ReuseAs_Status = reuse_as_and_status(IrInfo ^ reuse_as,
+        IrInfo ^ analysis_status),
+    sr_fixpoint_table_new_as(!.ModuleInfo, ProcInfo0, PPId, ReuseAs_Status,
+        !FixpointTable),
 
     % As the analysis changes the goal, we must update proc_info and
     % module_info:
@@ -215,6 +235,7 @@
 :- type ir_background_info
     --->    ir_background_info(
                 module_info     :: module_info,
+                pred_proc_id    :: pred_proc_id,
                 pred_info       :: pred_info,
                 proc_info       :: proc_info,
                 sharing_table   :: sharing_as_table,
@@ -224,21 +245,22 @@
                 debug_indirect  :: bool
             ).
 
-    % The type analysis_info gathers the analysis information that may change
-    % from goal to goal.
+    % The type ir_analysis_info gathers the analysis information that may
+    % change from goal to goal.
     %
 :- type ir_analysis_info
     --->    ir_analysis_info(
                 sharing_as      :: sharing_as,
                 reuse_as        :: reuse_as,
+                analysis_status :: analysis_status,
                 static_vars     :: set(prog_var),
                 fptable         :: sr_fixpoint_table
             ).
 
-:- func ir_background_info_init(module_info, pred_info, proc_info,
-    sharing_as_table, reuse_as_table) = ir_background_info.
+:- func ir_background_info_init(module_info, pred_proc_id, pred_info,
+    proc_info, sharing_as_table, reuse_as_table) = ir_background_info.
 
-ir_background_info_init(ModuleInfo, PredInfo, ProcInfo, SharingTable,
+ir_background_info_init(ModuleInfo, PPId, PredInfo, ProcInfo, SharingTable,
         ReuseTable) = BG :-
     % We don't need to keep track of any information regarding inserted
     % type-info arguments and alike, so we remove them from the list
@@ -252,62 +274,65 @@
     globals.lookup_bool_option(Globals, very_verbose, VeryVerbose),
     globals.lookup_bool_option(Globals, debug_indirect_reuse, DebugIndirect),
 
-    BG = ir_background_info(ModuleInfo, PredInfo, ProcInfo,
+    BG = ir_background_info(ModuleInfo, PPId, PredInfo, ProcInfo,
         SharingTable, ReuseTable, HeadVarsOfInterest, VeryVerbose,
         DebugIndirect).
 
-:- func analysis_info_init(pred_proc_id, sr_fixpoint_table) = ir_analysis_info.
+:- func ir_analysis_info_init(pred_proc_id, sr_fixpoint_table) =
+    ir_analysis_info.
 
-analysis_info_init(PPId, FixpointTable) = Info :-
-    ReuseAs = sr_fixpoint_table_get_final_as(PPId, FixpointTable),
-    Info = ir_analysis_info(sharing_as_init, ReuseAs, set.init, FixpointTable).
+ir_analysis_info_init(PPId, FixpointTable) = Info :-
+    ReuseAs_Sharing = sr_fixpoint_table_get_final_as(PPId, FixpointTable),
+    ReuseAs_Sharing = reuse_as_and_status(ReuseAs, Status),
+    Info = ir_analysis_info(sharing_as_init, ReuseAs, Status, set.init,
+        FixpointTable).
 
     % When analysing disjuncts (or switches) each branch yields its own
     % analysis information. This needs to be combined to form one single
     % analysis information to continue the analysis with.
     %
-:- pred analysis_info_combine(ir_background_info::in,
+:- pred ir_analysis_info_combine(ir_background_info::in,
     list(ir_analysis_info)::in, sr_fixpoint_table::in, ir_analysis_info::in,
     ir_analysis_info::out) is det.
 
-analysis_info_combine(BaseInfo, AnalysisInfoList, FixpointTable,
-        !AnalysisInfo) :-
-    % If the AnalysisInfoList = [], then the disjunct was simply empty, hence
+ir_analysis_info_combine(BaseInfo, IrInfoList, FixpointTable, !IrInfo) :-
+    % If the IrInfoList = [], then the disjunct was simply empty, hence
     % nothing to be done. Otherwise, compute the lub of each of the components
-    % of analysis_info.
+    % of ir_analysis_info.
     (
-        AnalysisInfoList = []
+        IrInfoList = []
     ;
-        AnalysisInfoList = [_ | _],
-        list.foldl(analysis_info_lub(BaseInfo), AnalysisInfoList,
-            !AnalysisInfo),
-        !:AnalysisInfo = !.AnalysisInfo ^ fptable := FixpointTable
+        IrInfoList = [_ | _],
+        list.foldl(ir_analysis_info_lub(BaseInfo), IrInfoList, !IrInfo),
+        !IrInfo ^ fptable := FixpointTable
     ).
 
-:- pred analysis_info_lub(ir_background_info::in, ir_analysis_info::in,
+:- pred ir_analysis_info_lub(ir_background_info::in, ir_analysis_info::in,
     ir_analysis_info::in, ir_analysis_info::out) is det.
 
-analysis_info_lub(BaseInfo, AnalysisInfo0, !AnalysisInfo):-
+ir_analysis_info_lub(BaseInfo, IrInfo0, !IrInfo):-
     ModuleInfo = BaseInfo ^ module_info,
     ProcInfo = BaseInfo ^ proc_info,
     % Lub of the sharing
     NewSharing = sharing_as_least_upper_bound(ModuleInfo, ProcInfo,
-        !.AnalysisInfo ^ sharing_as, AnalysisInfo0 ^ sharing_as),
+        !.IrInfo ^ sharing_as, IrInfo0 ^ sharing_as),
     % Lub of the reuse
     NewReuse = reuse_as_least_upper_bound(ModuleInfo, ProcInfo,
-        !.AnalysisInfo ^ reuse_as, AnalysisInfo0 ^ reuse_as),
+        !.IrInfo ^ reuse_as, IrInfo0 ^ reuse_as),
+    % Lub of the analysis status.
+    NewStatus = lub(!.IrInfo ^ analysis_status, IrInfo0 ^ analysis_status),
     % Union of the static vars
-    NewStaticVars = set.union(!.AnalysisInfo ^ static_vars,
-        AnalysisInfo0 ^ static_vars),
-    !:AnalysisInfo = ir_analysis_info(NewSharing, NewReuse, NewStaticVars,
-        !.AnalysisInfo ^ fptable).
+    NewStaticVars = set.union(!.IrInfo ^ static_vars, IrInfo0 ^ static_vars),
+    !:IrInfo = ir_analysis_info(NewSharing, NewReuse, NewStatus, NewStaticVars,
+        !.IrInfo ^ fptable).
 
 %-----------------------------------------------------------------------------%
 
 :- pred indirect_reuse_analyse_goal(ir_background_info::in, hlds_goal::in,
-    hlds_goal::out, ir_analysis_info::in, ir_analysis_info::out) is det.
+    hlds_goal::out, ir_analysis_info::in, ir_analysis_info::out,
+    dep_procs::in, dep_procs::out) is det.
 
-indirect_reuse_analyse_goal(BaseInfo, !Goal, !AnalysisInfo) :-
+indirect_reuse_analyse_goal(BaseInfo, !Goal, !IrInfo, !DepProcs) :-
     ModuleInfo = BaseInfo ^ module_info,
     PredInfo = BaseInfo ^ pred_info,
     ProcInfo = BaseInfo ^ proc_info,
@@ -315,27 +340,44 @@
     !.Goal = hlds_goal(GoalExpr0, GoalInfo0),
     (
         GoalExpr0 = conj(ConjType, Goals0),
-        list.map_foldl(indirect_reuse_analyse_goal(BaseInfo),
-            Goals0, Goals, !AnalysisInfo),
+        list.map_foldl2(indirect_reuse_analyse_goal(BaseInfo),
+            Goals0, Goals, !IrInfo, !DepProcs),
         GoalExpr = conj(ConjType, Goals),
         !:Goal = hlds_goal(GoalExpr, GoalInfo0)
     ;
         GoalExpr0 = plain_call(CalleePredId, CalleeProcId, CalleeArgs,
             _, _, _),
         verify_indirect_reuse(BaseInfo, CalleePredId, CalleeProcId,
-            CalleeArgs, GoalInfo0, GoalInfo, !AnalysisInfo),
+            CalleeArgs, GoalInfo0, GoalInfo, !IrInfo),
+        OldSharing = !.IrInfo ^ sharing_as,
         lookup_sharing_and_comb(ModuleInfo, PredInfo, ProcInfo, SharingTable,
-            CalleePredId, CalleeProcId, CalleeArgs,
-            !.AnalysisInfo ^ sharing_as, NewSharing),
-        !:AnalysisInfo = !.AnalysisInfo ^ sharing_as := NewSharing,
+            CalleePredId, CalleeProcId, CalleeArgs, OldSharing, NewSharing),
+        !IrInfo ^ sharing_as := NewSharing,
+
+        % 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(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(_),
+            \+ is_unify_or_compare_pred(CalleePredInfo)
+        ->
+            CalleePPId = proc(CalleePredId, CalleeProcId),
+            !:DepProcs = [CalleePPId | !.DepProcs]
+        ;
+            true
+        ),
+
         !:Goal = hlds_goal(GoalExpr0, GoalInfo)
     ;
         GoalExpr0 = generic_call(_GenDetails, _, _, _),
         Context = goal_info_get_context(GoalInfo0),
         context_to_string(Context, ContextString),
-        SharingAs = !.AnalysisInfo ^ sharing_as,
+        SharingAs = !.IrInfo ^ sharing_as,
         Msg = "generic call (" ++ ContextString ++ ")",
-        !:AnalysisInfo = !.AnalysisInfo ^ sharing_as :=
+        !IrInfo ^ sharing_as :=
             sharing_as_top_sharing_accumulate(top_cannot_improve(Msg),
                 SharingAs)
     ;
@@ -345,8 +387,8 @@
             Unification = construct(Var, _, _, _, HowToConstruct, _, _),
             (
                 HowToConstruct = construct_statically(_),
-                !:AnalysisInfo = !.AnalysisInfo ^ static_vars :=
-                    set.insert(!.AnalysisInfo ^ static_vars, Var)
+                !IrInfo ^ static_vars :=
+                    set.insert(!.IrInfo ^ static_vars, Var)
             ;
                 ( HowToConstruct = construct_dynamically
                 ; HowToConstruct = reuse_cell(_)
@@ -363,27 +405,27 @@
             unexpected(this_file,
             "complicated unification in indirect structure sharing analysis.")
         ),
-        !:AnalysisInfo = !.AnalysisInfo ^ sharing_as :=
-            add_unify_sharing(ModuleInfo, ProcInfo, Unification,
-            GoalInfo0, !.AnalysisInfo ^ sharing_as)
+        !IrInfo ^ sharing_as :=
+            add_unify_sharing(ModuleInfo, ProcInfo, Unification, GoalInfo0,
+                !.IrInfo ^ sharing_as)
     ;
         GoalExpr0 = disj(Goals0),
-        list.map2_foldl(
-            indirect_reuse_analyse_disj(BaseInfo, !.AnalysisInfo),
-            Goals0, Goals, AnalysisInfoList, !.AnalysisInfo ^ fptable,
-            NewFixpointTable),
-        analysis_info_combine(BaseInfo, AnalysisInfoList, NewFixpointTable,
-            !AnalysisInfo),
+        list.map2_foldl2(
+            indirect_reuse_analyse_disj(BaseInfo, !.IrInfo),
+            Goals0, Goals, IrInfoList, !.IrInfo ^ fptable, NewFixpointTable,
+            !DepProcs),
+        ir_analysis_info_combine(BaseInfo, IrInfoList, NewFixpointTable,
+            !IrInfo),
         GoalExpr = disj(Goals),
         !:Goal = hlds_goal(GoalExpr, GoalInfo0)
     ;
         GoalExpr0 = switch(A, B, Cases0),
-        list.map2_foldl(
-            indirect_reuse_analyse_case(BaseInfo, !.AnalysisInfo),
-            Cases0, Cases, AnalysisInfoList, !.AnalysisInfo ^ fptable,
-            NewFixpointTable),
-        analysis_info_combine(BaseInfo, AnalysisInfoList, NewFixpointTable,
-            !AnalysisInfo),
+        list.map2_foldl2(
+            indirect_reuse_analyse_case(BaseInfo, !.IrInfo),
+            Cases0, Cases, IrInfoList, !.IrInfo ^ fptable, NewFixpointTable,
+            !DepProcs),
+        ir_analysis_info_combine(BaseInfo, IrInfoList, NewFixpointTable,
+            !IrInfo),
         GoalExpr = switch(A, B, Cases),
         !:Goal = hlds_goal(GoalExpr, GoalInfo0)
     ;
@@ -391,43 +433,42 @@
         GoalExpr0 = negation(_Goal)
     ;
         GoalExpr0 = scope(A, SubGoal0),
-        indirect_reuse_analyse_goal(BaseInfo, SubGoal0, SubGoal,
-            !AnalysisInfo),
+        indirect_reuse_analyse_goal(BaseInfo, SubGoal0, SubGoal, !IrInfo,
+            !DepProcs),
         GoalExpr = scope(A, SubGoal),
         !:Goal = hlds_goal(GoalExpr, GoalInfo0)
     ;
         % Brief sketch:
-        % * AnalysisInfo0 --> IfGoal --> AnalysisInfoIfGoal,
-        % * AnalysisInfoIfGoal --> ThenGoal --> AnalysisInfoThenGoal,
-        % * update AnalysisInfo0 to include the latest state of the fixpoint
-        % table, yields AnalysisInfoElseGoal0
-        % * AnalysisInfoElseGoal0 --> ElseGoal --> AnalysisInfoElseGoal
-        % * and then compute the lub of AnalysisInfoThenGoal,
-        % and AnalysisInfoElseGoal. Make sure that the result contains
+        % * IrInfo0 --> IfGoal --> IrInfoIfGoal,
+        % * IrInfoIfGoal --> ThenGoal --> IrInfoThenGoal,
+        % * update IrInfo0 to include the latest state of the fixpoint
+        % table, yields IrInfoElseGoal0
+        % * IrInfoElseGoal0 --> ElseGoal --> IrInfoElseGoal
+        % * and then compute the lub of IrInfoThenGoal,
+        % and IrInfoElseGoal. Make sure that the result contains
         % the latest state of the fixpoint table, i.e., the one recorded
-        % in AnalysisInfoElseGoal.
+        % in IrInfoElseGoal.
         GoalExpr0 = if_then_else(A, IfGoal0, ThenGoal0, ElseGoal0),
-        AnalysisInfo0 = !.AnalysisInfo,
+        IrInfo0 = !.IrInfo,
         indirect_reuse_analyse_goal(BaseInfo, IfGoal0, IfGoal,
-            AnalysisInfo0, AnalysisInfoIfGoal),
+            IrInfo0, IrInfoIfGoal, !DepProcs),
         indirect_reuse_analyse_goal(BaseInfo, ThenGoal0, ThenGoal,
-            AnalysisInfoIfGoal, AnalysisInfoThenGoal),
-        AnalysisInfoElseGoal0 = AnalysisInfo0 ^ fptable :=
-            AnalysisInfoThenGoal ^ fptable,
+            IrInfoIfGoal, IrInfoThenGoal, !DepProcs),
+        IrInfoElseGoal0 = IrInfo0 ^ fptable := IrInfoThenGoal ^ fptable,
         indirect_reuse_analyse_goal(BaseInfo, ElseGoal0, ElseGoal,
-            AnalysisInfoElseGoal0, AnalysisInfoElseGoal),
-        analysis_info_lub(BaseInfo, AnalysisInfoThenGoal,
-            AnalysisInfoElseGoal, !:AnalysisInfo),
+            IrInfoElseGoal0, IrInfoElseGoal, !DepProcs),
+        ir_analysis_info_lub(BaseInfo, IrInfoThenGoal, IrInfoElseGoal,
+            !:IrInfo),
         GoalExpr = if_then_else(A, IfGoal, ThenGoal, ElseGoal),
         !:Goal = hlds_goal(GoalExpr, GoalInfo0)
     ;
         GoalExpr0 = call_foreign_proc(Attributes, ForeignPredId, ForeignProcId,
             _Args, _ExtraArgs, _MaybeTraceRuntimeCond, _Impl),
         Context = goal_info_get_context(GoalInfo0),
-        !:AnalysisInfo = !.AnalysisInfo ^ sharing_as :=
+        !IrInfo ^ sharing_as :=
             add_foreign_proc_sharing(ModuleInfo, ProcInfo,
             proc(ForeignPredId, ForeignProcId), Attributes, Context,
-            !.AnalysisInfo ^ sharing_as)
+            !.IrInfo ^ sharing_as)
     ;
         GoalExpr0 = shorthand(_),
         % These should have been expanded out by now.
@@ -435,34 +476,36 @@
     ).
 
     % Analyse each branch of a disjunction with respect to an input
-    % analysis_info, producing a resulting analysis_info, and possibly
+    % ir_analysis_info, producing a resulting ir_analysis_info, and possibly
     % updating the state of the sr_fixpoint_table.
     %
 :- pred indirect_reuse_analyse_disj(ir_background_info::in,
     ir_analysis_info::in, hlds_goal::in, hlds_goal::out, ir_analysis_info::out,
-    sr_fixpoint_table::in, sr_fixpoint_table::out) is det.
+    sr_fixpoint_table::in, sr_fixpoint_table::out,
+    dep_procs::in, dep_procs::out) is det.
 
-indirect_reuse_analyse_disj(BaseInfo, AnalysisInfo0, Goal0, Goal, AnalysisInfo,
-        !FixpointTable) :-
-    % Replace the state of the fixpoint_table in AnalysisInfo0:
-    NewAnalysisInfo = AnalysisInfo0 ^ fptable := !.FixpointTable,
-    indirect_reuse_analyse_goal(BaseInfo, Goal0, Goal, NewAnalysisInfo,
-        AnalysisInfo),
-    !:FixpointTable = AnalysisInfo ^ fptable.
+indirect_reuse_analyse_disj(BaseInfo, IrInfo0, Goal0, Goal, IrInfo,
+        !FixpointTable, !DepProcs) :-
+    % Replace the state of the fixpoint_table in IrInfo0:
+    NewIrInfo = IrInfo0 ^ fptable := !.FixpointTable,
+    indirect_reuse_analyse_goal(BaseInfo, Goal0, Goal, NewIrInfo, IrInfo,
+        !DepProcs),
+    !:FixpointTable = IrInfo ^ fptable.
 
     % Similar to indirect_reuse_analyse_disj.
 :- pred indirect_reuse_analyse_case(ir_background_info::in,
     ir_analysis_info::in, case::in, case::out, ir_analysis_info::out,
-    sr_fixpoint_table::in, sr_fixpoint_table::out) is det.
+    sr_fixpoint_table::in, sr_fixpoint_table::out,
+    dep_procs::in, dep_procs::out) is det.
 
-indirect_reuse_analyse_case(BaseInfo, AnalysisInfo0, Case0, Case, AnalysisInfo,
-        !FixpointTable) :-
+indirect_reuse_analyse_case(BaseInfo, IrInfo0, Case0, Case, IrInfo,
+        !FixpointTable, !DepProcs) :-
     Case0 = case(MainConsId, OtherConsIds, Goal0),
-    % Replace the state of the fixpoint_table in AnalysisInfo0:
-    NewAnalysisInfo = AnalysisInfo0 ^ fptable := !.FixpointTable,
-    indirect_reuse_analyse_goal(BaseInfo, Goal0, Goal, NewAnalysisInfo,
-        AnalysisInfo),
-    !:FixpointTable = AnalysisInfo ^ fptable,
+    % Replace the state of the fixpoint_table in IrInfo0:
+    NewIrInfo = IrInfo0 ^ fptable := !.FixpointTable,
+    indirect_reuse_analyse_goal(BaseInfo, Goal0, Goal, NewIrInfo, IrInfo,
+        !DepProcs),
+    !:FixpointTable = IrInfo ^ fptable,
     Case = case(MainConsId, OtherConsIds, Goal).
 
 %-----------------------------------------------------------------------------%
@@ -480,10 +523,11 @@
     ir_analysis_info::in, ir_analysis_info::out) is det.
 
 verify_indirect_reuse(BaseInfo, CalleePredId, CalleeProcId, CalleeArgs,
-        !GoalInfo, !AnalysisInfo) :-
+        !GoalInfo, !IrInfo) :-
     % Find the reuse information of the called procedure in the reuse table:
     CalleePPId = proc(CalleePredId, CalleeProcId),
-    lookup_reuse_as(BaseInfo, CalleePPId, !AnalysisInfo, FormalReuseAs),
+    lookup_reuse_as(BaseInfo, CalleePPId, !IrInfo, FormalReuseAs_Status),
+    FormalReuseAs_Status = reuse_as_and_status(FormalReuseAs, LookupStatus),
 
     (
         % If there is no reuse, then nothing can be done.
@@ -495,8 +539,8 @@
     ->
         % With unconditional reuse, we need to mark that the call is always
         % a reuse call.
-        reuse_as_add_unconditional(!.AnalysisInfo ^ reuse_as, NewReuseAs),
-        !:AnalysisInfo = !.AnalysisInfo ^ reuse_as := NewReuseAs,
+        reuse_as_add_unconditional(!.IrInfo ^ reuse_as, NewReuseAs),
+        !:IrInfo = !.IrInfo ^ reuse_as := NewReuseAs,
         goal_info_set_reuse(reuse(reuse_call(unconditional_reuse)), !GoalInfo),
         Reason = callee_has_only_unconditional_reuse
     ;
@@ -510,12 +554,12 @@
             % verifying reuse explicitly, as we don't have any information
             % anymore about existing (and therefore non-existing) sharing
             % pairs. In this case, reuse is not allowed.
-            sharing_as_is_top(!.AnalysisInfo ^ sharing_as)
+            sharing_as_is_top(!.IrInfo ^ sharing_as)
         ->
             % no need to update anything
             Reason = current_sharing_is_top
         ;
-            verify_indirect_reuse_2(BaseInfo, !.AnalysisInfo, !.GoalInfo,
+            verify_indirect_reuse_2(BaseInfo, !.IrInfo, !.GoalInfo,
                 CalleePPId, CalleeArgs, FormalReuseAs, NewAndRenamedReuseAs,
                 NotDeadVars),
             (
@@ -527,18 +571,17 @@
                 reuse_as_all_unconditional_reuses(NewAndRenamedReuseAs)
             ->
                 % Update reuse information and goal_info:
-                reuse_as_add_unconditional(!.AnalysisInfo ^ reuse_as,
-                    NewReuseAs),
-                !:AnalysisInfo = !.AnalysisInfo ^ reuse_as := NewReuseAs,
+                reuse_as_add_unconditional(!.IrInfo ^ reuse_as, NewReuseAs),
+                !IrInfo ^ reuse_as := NewReuseAs,
                 goal_info_set_reuse(reuse(reuse_call(unconditional_reuse)),
                     !GoalInfo),
                 Reason = reuse_is_unconditional
             ;
                 % Update reuse information and goal_info:
                 reuse_as_least_upper_bound(BaseInfo ^ module_info,
-                    BaseInfo ^ proc_info, !.AnalysisInfo ^ reuse_as,
+                    BaseInfo ^ proc_info, !.IrInfo ^ reuse_as,
                     NewAndRenamedReuseAs, NewReuseAs),
-                !:AnalysisInfo = !.AnalysisInfo ^ reuse_as := NewReuseAs,
+                !IrInfo ^ reuse_as := NewReuseAs,
                 goal_info_set_reuse(
                     potential_reuse(reuse_call(conditional_reuse)),
                     !GoalInfo),
@@ -547,6 +590,10 @@
         )
     ),
 
+    % Combine the status of the reuse information with the status of the
+    % current analysis.
+    !IrInfo ^ analysis_status := lub(LookupStatus, !.IrInfo ^ analysis_status),
+
     % Output the reasoning behind the result.
     trace [io(!IO)] (
         DebugIndirect = BaseInfo ^ debug_indirect,
@@ -572,23 +619,21 @@
     ).
 
 :- pred lookup_reuse_as(ir_background_info::in, pred_proc_id::in,
-    ir_analysis_info::in, ir_analysis_info::out, reuse_as::out) is det.
+    ir_analysis_info::in, ir_analysis_info::out, reuse_as_and_status::out)
+    is det.
 
-lookup_reuse_as(BaseInfo, PPId, !AnalysisInfo, ReuseAs) :-
+lookup_reuse_as(BaseInfo, PPId, !IrInfo, ReuseAs) :-
     (
         % Check in the fixpoint table
-        sr_fixpoint_table_get_as(PPId, ReuseAs0, !.AnalysisInfo ^ fptable,
+        sr_fixpoint_table_get_as(PPId, ReuseAs0, !.IrInfo ^ fptable,
             NewFixpointTable)
     ->
         ReuseAs = ReuseAs0,
-        !:AnalysisInfo = !.AnalysisInfo ^ fptable := NewFixpointTable
+        !IrInfo ^ fptable := NewFixpointTable
     ;
         % Or check in the reuse table
-        ReuseAs0 = reuse_as_table_search(PPId, BaseInfo ^ reuse_table)
-    ->
-        ReuseAs = ReuseAs0
-    ;
-        ReuseAs = reuse_as_init
+        ReuseAs = get_reuse_as(BaseInfo ^ module_info, BaseInfo ^ reuse_table,
+            PPId)
     ).
 
     % Verify whether the caller's environment satisfies the reuse conditions
@@ -603,12 +648,12 @@
     hlds_goal_info::in, pred_proc_id::in, list(prog_var)::in, reuse_as::in,
     reuse_as::out, prog_vars::out) is det.
 
-verify_indirect_reuse_2(BaseInfo, AnalysisInfo, GoalInfo, CalleePPId,
+verify_indirect_reuse_2(BaseInfo, IrInfo, GoalInfo, CalleePPId,
         CalleeArgs, FormalReuseAs, NewReuseAs, NotDeadVars):-
     ModuleInfo = BaseInfo ^ module_info,
     PredInfo = BaseInfo ^ pred_info,
     ProcInfo = BaseInfo ^ proc_info,
-    SharingAs = AnalysisInfo ^ sharing_as,
+    SharingAs = IrInfo ^ sharing_as,
     proc_info_get_vartypes(ProcInfo, ActualVarTypes),
     pred_info_get_typevarset(PredInfo, CallerTypeVarSet),
     pred_info_get_univ_quant_tvars(PredInfo, CallerHeadTypeParams),
@@ -619,7 +664,7 @@
     LiveData = livedata_init_at_goal(ModuleInfo, ProcInfo, GoalInfo,
         SharingAs),
     ProjectedLiveData = livedata_project(CalleeArgs, LiveData),
-    StaticVars = set.to_sorted_list(AnalysisInfo ^ static_vars),
+    StaticVars = set.to_sorted_list(IrInfo ^ static_vars),
  
     reuse_as_satisfied(ModuleInfo, ProcInfo, ProjectedLiveData,
         SharingAs, StaticVars, ActualReuseAs, Result),
@@ -681,11 +726,12 @@
 % Structure reuse fixpoint table
 %
 
-:- type sr_fixpoint_table == fixpoint_table(pred_proc_id, reuse_as).
+:- type sr_fixpoint_table ==
+    fixpoint_table(pred_proc_id, reuse_as_and_status).
 
     % Initialise the fixpoint table for the given set of pred_proc_id's.
     %
-:- func sr_fixpoint_table_init(list(pred_proc_id), reuse_as_table)
+:- func sr_fixpoint_table_init(module_info, list(pred_proc_id), reuse_as_table)
     = sr_fixpoint_table.
 
     % Add the results of a new analysis pass to the already existing
@@ -715,7 +761,7 @@
     % Software error if the procedure is not in the fixpoint table.
     %
 :- pred sr_fixpoint_table_new_as(module_info::in, proc_info::in,
-    pred_proc_id::in, reuse_as::in,
+    pred_proc_id::in, reuse_as_and_status::in,
     sr_fixpoint_table::in, sr_fixpoint_table::out) is det.
 
     % Retrieve the structure reuse information for a given pred_proc_id.
@@ -727,7 +773,7 @@
     %
     % If the id is not part of the fixpoint table: fail.
     %
-:- pred sr_fixpoint_table_get_as(pred_proc_id::in, reuse_as::out,
+:- pred sr_fixpoint_table_get_as(pred_proc_id::in, reuse_as_and_status::out,
     sr_fixpoint_table::in, sr_fixpoint_table::out) is semidet.
 
 :- func sr_fixpoint_table_get_short_description(pred_proc_id,
@@ -738,27 +784,40 @@
     % Software error if the procedure is not in the table.
     %
 :- func sr_fixpoint_table_get_final_as(pred_proc_id,
-    sr_fixpoint_table) = reuse_as.
+    sr_fixpoint_table) = reuse_as_and_status.
 
     % Same as sr_fixpoint_table_get_final_as, yet fails instead of aborting
     % if the procedure is not in the table.
     %
 :- pred sr_fixpoint_table_get_final_as_semidet(pred_proc_id::in,
-    sr_fixpoint_table::in, reuse_as::out) is semidet.
+    sr_fixpoint_table::in, reuse_as_and_status::out) is semidet.
 
 %-----------------------------------------------------------------------------%
 
-:- func get_reuse_as(reuse_as_table, pred_proc_id) = reuse_as.
+:- func get_reuse_as(module_info, reuse_as_table, pred_proc_id) =
+    reuse_as_and_status.
 
-get_reuse_as(ReuseTable, PPId) = ReuseAs :-
-    ( ReuseAs0 = reuse_as_table_search(PPId, ReuseTable) ->
+get_reuse_as(ModuleInfo, ReuseTable, PPId) = ReuseAs :-
+    ( reuse_as_table_search(PPId, ReuseTable, ReuseAs0) ->
         ReuseAs = ReuseAs0
     ;
-        ReuseAs = reuse_as_init
+        PPId = proc(PredId, _),
+        module_info_pred_info(ModuleInfo, PredId, PredInfo),
+        (
+            ( is_unify_or_compare_pred(PredInfo)
+            ; pred_info_get_import_status(PredInfo, status_external(_))
+            )
+        ->
+            Status = optimal
+        ;
+            % XXX not sure about this
+            Status = suboptimal
+        ),
+        ReuseAs = reuse_as_and_status(reuse_as_init, Status)
     ).
 
-sr_fixpoint_table_init(Keys, ReuseTable) = Table :-
-    Table = init_fixpoint_table(get_reuse_as(ReuseTable), Keys).
+sr_fixpoint_table_init(ModuleInfo, Keys, ReuseTable) = Table :-
+    Table = init_fixpoint_table(get_reuse_as(ModuleInfo, ReuseTable), Keys).
 
 sr_fixpoint_table_new_run(!Table) :-
     fixpoint_table.new_run(!Table).
@@ -771,7 +830,7 @@
 sr_fixpoint_table_description(Table) = fixpoint_table.description(Table).
 
 sr_fixpoint_table_new_as(ModuleInfo, ProcInfo, Id, ReuseAs, !Table) :-
-    add_to_fixpoint_table(reuse_as_subsumed_by(ModuleInfo, ProcInfo),
+    add_to_fixpoint_table(reuse_as_and_status_subsumed_by(ModuleInfo, ProcInfo),
         Id, ReuseAs, !Table).
 
 sr_fixpoint_table_get_as(PPId, ReuseAs, !Table) :-
@@ -783,8 +842,11 @@
     ;
         Rec = "(non-rec)"
     ),
-    ( sr_fixpoint_table_get_final_as_semidet(PPId, Table, As) ->
-        Descr0 = reuse_as_short_description(As)
+    (
+        sr_fixpoint_table_get_final_as_semidet(PPId, Table,
+            reuse_as_and_status(ReuseAs, _))
+    ->
+        Descr0 = reuse_as_short_description(ReuseAs)
     ;
         Descr0 = "-"
     ),
Index: compiler/structure_reuse.versions.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/structure_reuse.versions.m,v
retrieving revision 1.13
diff -u -r1.13 structure_reuse.versions.m
--- compiler/structure_reuse.versions.m	17 Apr 2008 04:21:51 -0000	1.13
+++ compiler/structure_reuse.versions.m	7 May 2008 05:04:51 -0000
@@ -64,6 +64,7 @@
 :- import_module mdbcomp.prim_data.
 :- import_module parse_tree.prog_util.
 
+:- import_module bool.
 :- import_module list.
 :- import_module map.
 :- import_module maybe.
@@ -94,7 +95,17 @@
     %   to correctly update the reuse annotations.
     %
 create_reuse_procedures(ReuseTable, !ModuleInfo, !IO):-
-    PPIds = map.keys(ReuseTable),
+    AllPPIds = map.keys(ReuseTable),
+
+    % Ignore reuse table entries for imported procedures.
+    DefinedHere = (pred(PPId::in) is semidet :-
+        PPId = proc(PredId, _),
+        module_info_pred_info(!.ModuleInfo, PredId, PredInfo),
+        pred_info_get_import_status(PredInfo, Status),
+        status_defined_in_this_module(Status) = yes
+    ),
+    list.filter(DefinedHere, AllPPIds, PPIds),
+
     CondPPIds = list.filter(has_conditional_reuse(ReuseTable), PPIds),
     UncondPPIds = list.filter(has_unconditional_reuse(ReuseTable), PPIds),
 
@@ -110,14 +121,14 @@
 :- pred has_conditional_reuse(reuse_as_table::in, pred_proc_id::in) is semidet.
 
 has_conditional_reuse(ReuseTable, PPId) :-
-    ReuseAs = reuse_as_table_search(PPId, ReuseTable),
+    reuse_as_table_search(PPId, ReuseTable, reuse_as_and_status(ReuseAs, _)),
     reuse_as_conditional_reuses(ReuseAs).
 
 :- pred has_unconditional_reuse(reuse_as_table::in, pred_proc_id::in)
     is semidet.
 
 has_unconditional_reuse(ReuseTable, PPId) :-
-    ReuseAs = reuse_as_table_search(PPId, ReuseTable),
+    reuse_as_table_search(PPId, ReuseTable, reuse_as_and_status(ReuseAs, _)),
     reuse_as_all_unconditional_reuses(ReuseAs).
 
 %------------------------------------------------------------------------------%
Index: compiler/structure_sharing.analysis.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/structure_sharing.analysis.m,v
retrieving revision 1.31
diff -u -r1.31 structure_sharing.analysis.m
--- compiler/structure_sharing.analysis.m	27 Mar 2008 02:29:42 -0000	1.31
+++ compiler/structure_sharing.analysis.m	7 May 2008 05:04:51 -0000
@@ -573,7 +573,8 @@
             status_defined_in_this_module(PredImportStatus) = yes,
             module_info_pred_info(ModuleInfo, CalleePredId, CalleePredInfo),
             pred_info_get_import_status(CalleePredInfo, CalleeImportStatus),
-            CalleeImportStatus = status_imported(_)
+            CalleeImportStatus = status_imported(_),
+            \+ is_unify_or_compare_pred(CalleePredInfo)
         ->
             !:DepProcs = [CalleePPId | !.DepProcs]
         ;
@@ -896,35 +897,30 @@
 
 write_pred_sharing_info(ModuleInfo, PredId, !IO) :-
     module_info_pred_info(ModuleInfo, PredId, PredInfo),
-    should_write_sharing_info(ModuleInfo, PredId, PredInfo, ShouldWrite),
+    PredName = pred_info_name(PredInfo),
+    ProcIds = pred_info_procids(PredInfo),
+    PredOrFunc = pred_info_is_pred_or_func(PredInfo),
+    ModuleName = pred_info_module(PredInfo),
+    pred_info_get_procedures(PredInfo, ProcTable),
+    pred_info_get_context(PredInfo, Context),
+    SymName = qualified(ModuleName, PredName),
+    pred_info_get_typevarset(PredInfo, TypeVarSet),
+    list.foldl(
+        write_proc_sharing_info(ModuleInfo, PredId, PredInfo, ProcTable,
+            PredOrFunc, SymName, Context, TypeVarSet),
+        ProcIds, !IO).
+
+:- pred write_proc_sharing_info(module_info::in, pred_id::in, pred_info::in,
+    proc_table::in, pred_or_func::in, sym_name::in, prog_context::in,
+    tvarset::in, proc_id::in, io::di, io::uo) is det.
+
+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),
     (
         ShouldWrite = yes,
-        PredName = pred_info_name(PredInfo),
-        ProcIds = pred_info_procids(PredInfo),
-        PredOrFunc = pred_info_is_pred_or_func(PredInfo),
-        ModuleName = pred_info_module(PredInfo),
-        pred_info_get_procedures(PredInfo, ProcTable),
-        pred_info_get_context(PredInfo, Context),
-        SymName = qualified(ModuleName, PredName),
-        pred_info_get_typevarset(PredInfo, TypeVarSet),
-        list.foldl(
-            write_proc_sharing_info(PredId, ProcTable, PredOrFunc,
-                SymName, Context, TypeVarSet),
-            ProcIds, !IO)
-    ;
-        ShouldWrite = no
-    ).
 
-:- pred write_proc_sharing_info(pred_id::in, proc_table::in,
-    pred_or_func::in, sym_name::in, prog_context::in, tvarset::in,
-    proc_id::in, io::di, io::uo) is det.
-
-write_proc_sharing_info(_PredId, ProcTable, PredOrFunc, SymName, Context,
-        TypeVarSet, ProcId, !IO) :-
-    globals.io_lookup_bool_option(structure_sharing_analysis,
-        SharingAnalysis, !IO),
-    (
-        SharingAnalysis = yes,
         map.lookup(ProcTable, ProcId, ProcInfo),
         proc_info_get_structure_sharing(ProcInfo, MaybeSharingStatus),
         proc_info_declared_argmodes(ProcInfo, Modes),
@@ -944,7 +940,7 @@
             Context, HeadVars, yes(VarSet), HeadVarTypes, yes(TypeVarSet),
             MaybeSharing, !IO)
     ;
-        SharingAnalysis = no
+        ShouldWrite = no
     ).
 
 %-----------------------------------------------------------------------------%
@@ -1125,7 +1121,8 @@
         !AnalysisInfo) :-
     PPId = proc(PredId, ProcId),
     module_info_pred_proc_info(ModuleInfo, PredId, ProcId, PredInfo, ProcInfo),
-    should_write_sharing_info(ModuleInfo, PredId, PredInfo, ShouldWrite),
+    should_write_sharing_info(ModuleInfo, PredId, ProcId, PredInfo,
+        allow_type_spec_preds, ShouldWrite),
     (
         ShouldWrite = yes,
         (
@@ -1253,27 +1250,31 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred should_write_sharing_info(module_info::in, pred_id::in, pred_info::in,
-    bool::out) is det.
+:- type allow_type_spec_preds
+    --->    allow_type_spec_preds
+    ;       disallow_type_spec_preds.
+
+:- 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.
 
-should_write_sharing_info(ModuleInfo, PredId, PredInfo, ShouldWrite) :-
-    pred_info_get_import_status(PredInfo, ImportStatus),
-    module_info_get_type_spec_info(ModuleInfo, TypeSpecInfo),
-    TypeSpecInfo = type_spec_info(_, TypeSpecForcePreds, _, _),
+should_write_sharing_info(ModuleInfo, PredId, ProcId, PredInfo,
+        AllowTypeSpecPreds, ShouldWrite) :-
     (
-        (
-            ImportStatus = status_exported
-        ;
-            ImportStatus = status_opt_exported
-        ;
-            ImportStatus = status_exported_to_submodules
-        ),
+        procedure_is_exported(ModuleInfo, PredInfo, ProcId),
         \+ is_unify_or_compare_pred(PredInfo),
 
-        % 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 error.
-        \+ set.member(PredId, TypeSpecForcePreds)
+        (
+            AllowTypeSpecPreds = allow_type_spec_preds
+        ;
+            AllowTypeSpecPreds = disallow_type_spec_preds,
+            % 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
+            % error.
+            module_info_get_type_spec_info(ModuleInfo, TypeSpecInfo),
+            TypeSpecInfo = type_spec_info(_, TypeSpecForcePreds, _, _),
+            \+ set.member(PredId, TypeSpecForcePreds)
+        )
     ->
         ShouldWrite = yes
     ;
Index: compiler/structure_sharing.domain.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/structure_sharing.domain.m,v
retrieving revision 1.31
diff -u -r1.31 structure_sharing.domain.m
--- compiler/structure_sharing.domain.m	23 Apr 2008 05:16:49 -0000	1.31
+++ compiler/structure_sharing.domain.m	7 May 2008 05:04:52 -0000
@@ -801,9 +801,9 @@
 lookup_sharing_and_comb(ModuleInfo, PredInfo, ProcInfo, SharingTable, 
         PredId, ProcId, ActualVars, !Sharing):- 
     PPId = proc(PredId, ProcId),
-    
-    % XXX make use of the status once the structure reuse passes use the
-    % analysis framework
+
+    % XXX do we need to combine the analysis status of sharing information we
+    % use with the analysis status of direct and indirect analyses?
     lookup_sharing_or_predict(ModuleInfo, SharingTable, PPId, FormalSharing,
         _Status, _IsPredicted),


--------------------------------------------------------------------------
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