[m-rev.] for review: analysis framework (2/2)

Peter Wang wangp at students.cs.mu.OZ.AU
Mon Jan 16 14:14:00 AEDT 2006


Index: compiler/add_pragma.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/add_pragma.m,v
retrieving revision 1.19
diff -u -r1.19 add_pragma.m
--- compiler/add_pragma.m	28 Nov 2005 04:11:37 -0000	1.19
+++ compiler/add_pragma.m	13 Jan 2006 02:52:55 -0000
@@ -105,6 +105,7 @@
 
 :- implementation.
 
+:- import_module analysis.
 :- import_module backend_libs.
 :- import_module backend_libs.foreign.
 :- import_module check_hlds.mode_util.
@@ -599,7 +600,10 @@
     ->
         module_info_get_trailing_info(!.ModuleInfo, TrailingInfo0),
         proc_id_to_int(ProcId, ModeNum),
-        map.set(TrailingInfo0, proc(PredId, ProcId), TrailingStatus,
+        % The `optimal' part is only used by --intermodule-analysis
+        % whereas this is for --intermodule-optimisation.
+        % It should not matter what we put there.
+        map.set(TrailingInfo0, proc(PredId, ProcId), {TrailingStatus, optimal},
             TrailingInfo),
         module_info_set_trailing_info(TrailingInfo, !ModuleInfo)
     ;
Index: compiler/hlds_module.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_module.m,v
retrieving revision 1.127
diff -u -r1.127 hlds_module.m
--- compiler/hlds_module.m	28 Nov 2005 04:11:42 -0000	1.127
+++ compiler/hlds_module.m	5 Jan 2006 00:37:17 -0000
@@ -107,7 +107,7 @@
     % Map from proc to an indication of whether or not it
     % modifies the trail.
     %
-:- type trailing_info == map(pred_proc_id, trailing_status).
+:- type trailing_info == map(pred_proc_id, {trailing_status, analysis_status}).
 
     % List of procedures for which there are user-requested type
     % specializations, and a list of predicates which should be
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.371
diff -u -r1.371 mercury_compile.m
--- compiler/mercury_compile.m	3 Jan 2006 04:07:50 -0000	1.371
+++ compiler/mercury_compile.m	4 Jan 2006 07:15:00 -0000
@@ -1512,13 +1512,19 @@
             !IO),
         (
             IntermodAnalysis = yes,
-            module_info_get_analysis_info(HLDS50, AnalysisInfo),
-            analysis__write_analysis_files(
-                module_name_to_module_id(ModuleName), AnalysisInfo, !IO)
+            module_info_get_analysis_info(HLDS50, AnalysisInfo0),
+            module_info_get_all_deps(HLDS50, ImportedModules),
+            ModuleId = module_name_to_module_id(ModuleName),
+            ImportedModuleIds = set.map(module_name_to_module_id,
+                ImportedModules),
+            analysis__write_analysis_files(ModuleId, ImportedModuleIds,
+                AnalysisInfo0, AnalysisInfo, !IO),
+            module_info_set_analysis_info(AnalysisInfo, HLDS50, HLDS50B)
         ;
-            IntermodAnalysis = no
+            IntermodAnalysis = no,
+            HLDS50B = HLDS50
         ),
-        maybe_generate_rl_bytecode(Verbose, MaybeRLFile, HLDS50, HLDS51, !IO),
+        maybe_generate_rl_bytecode(Verbose, MaybeRLFile, HLDS50B, HLDS51, !IO),
         (
             ( Target = c
             ; Target = asm
Index: compiler/mmc_analysis.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mmc_analysis.m,v
retrieving revision 1.9
diff -u -r1.9 mmc_analysis.m
--- compiler/mmc_analysis.m	28 Oct 2005 02:10:22 -0000	1.9
+++ compiler/mmc_analysis.m	15 Dec 2005 02:19:05 -0000
@@ -36,6 +36,7 @@
 :- import_module parse_tree.modules.
 :- import_module parse_tree.prog_out.
 :- import_module parse_tree.prog_util.
+:- import_module transform_hlds.trailing_analysis.
 :- import_module transform_hlds.unused_args.
 
 :- import_module bool.
@@ -45,10 +46,14 @@
 :- instance compiler(mmc) where [
     compiler_name(mmc) = "mmc",
 
-    analyses(mmc, "unused_args") =
+    analyses(mmc, "trailing_info") =
         'new analysis_type'(
-            unit1 `with_type` unit(unused_args_func_info),
             unit1 `with_type` unit(any_call),
+            unit1 `with_type` unit(trailing_analysis_answer)),
+
+    analyses(mmc, "unused_args") =
+        'new analysis_type'(
+            unit1 `with_type` unit(unused_args_call),
             unit1 `with_type` unit(unused_args_answer)),
 
     module_id_to_file_name(mmc, ModuleId, Ext, FileName) -->
Index: compiler/trailing_analysis.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/trailing_analysis.m,v
retrieving revision 1.4
diff -u -r1.4 trailing_analysis.m
--- compiler/trailing_analysis.m	24 Dec 2005 08:44:12 -0000	1.4
+++ compiler/trailing_analysis.m	6 Jan 2006 02:21:39 -0000
@@ -53,6 +53,7 @@
 :- module transform_hlds.trailing_analysis.
 :- interface.
 
+:- import_module analysis.
 :- import_module hlds.hlds_module.
 :- import_module hlds.hlds_pred.
 
@@ -70,6 +71,14 @@
 :- pred write_pragma_trailing_info(module_info::in, trailing_info::in,
     pred_id::in, io::di, io::uo) is det.
 
+    % Types and instances for the intermodule analysis framework.
+    %
+:- type trailing_analysis_answer.
+:- instance analysis(any_call, trailing_analysis_answer).
+:- instance partial_order(trailing_analysis_answer).
+:- instance answer_pattern(trailing_analysis_answer).
+:- instance to_string(trailing_analysis_answer).
+
 %----------------------------------------------------------------------------%
 %----------------------------------------------------------------------------%
 
@@ -96,6 +105,7 @@
 :- import_module parse_tree.prog_util.
 :- import_module parse_tree.prog_type.
 :- import_module transform_hlds.dependency_graph.
+:- import_module transform_hlds.mmc_analysis.
 
 :- import_module bool.
 :- import_module list.
@@ -155,20 +165,22 @@
 
 :- type proc_result
     --->    proc_result(
-                ppid   :: pred_proc_id,
-                status :: trailing_status
+                ppid            :: pred_proc_id,
+                status          :: trailing_status,
+                analysis_status :: analysis_status
             ).
 
 :- pred process_scc(bool::in, bool::in, scc::in,
     module_info::in, module_info::out, io::di, io::uo) is det.
 
 process_scc(Debug, Pass1Only, SCC, !ModuleInfo, !IO) :-
-    ProcResults = check_procs_for_trail_mods(SCC, !.ModuleInfo),
+    check_procs_for_trail_mods(SCC, ProcResults, !ModuleInfo, !IO),
     % 
     % The `Results' above are the results of analysing each individual
     % procedure in the SCC - we now have to combine them in a meaningful way.   
     %
     Status = combine_individual_proc_results(ProcResults),
+    AnalysisStatus = combine_individual_proc_statuses(ProcResults),
     %
     % Print out debugging information.
     %
@@ -183,10 +195,21 @@
     %
     module_info_get_trailing_info(!.ModuleInfo, TrailingInfo0),
     Update = (pred(PPId::in, Info0::in, Info::out) is det :-
-        Info = Info0 ^ elem(PPId) := Status
+        Info = Info0 ^ elem(PPId) := {Status, AnalysisStatus}
     ),
     list.foldl(Update, SCC, TrailingInfo0, TrailingInfo),
     module_info_set_trailing_info(TrailingInfo, !ModuleInfo),
+    %
+    % Record the analysis results for the intermodule analysis
+    %
+    globals__io_lookup_bool_option(intermodule_analysis, Intermod, !IO),
+    (
+        Intermod = yes,
+        record_trailing_analysis_results(Status, AnalysisStatus, SCC,
+            !ModuleInfo)
+    ;
+        Intermod = no
+    ),
     (
         Pass1Only = no,
         list.foldl(annotate_proc, SCC, !ModuleInfo)
@@ -196,10 +219,12 @@
 
     % Check each procedure in the SCC individually.
     %
-:- func check_procs_for_trail_mods(scc, module_info) = proc_results.
+:- pred check_procs_for_trail_mods(scc::in, proc_results::out,
+        module_info::in, module_info::out, io::di, io::uo) is det.
 
-check_procs_for_trail_mods(SCC, ModuleInfo) = Result :-
-    list.foldl(check_proc_for_trail_mods(SCC, ModuleInfo), SCC, [], Result).
+check_procs_for_trail_mods(SCC, Result, !ModuleInfo, !IO) :-
+    list.foldl3(check_proc_for_trail_mods(SCC), SCC, [], Result,
+        !ModuleInfo, !IO).
 
     % Examine how the procedures interact with other procedures that
     % are mutually-recursive to them.
@@ -230,60 +255,76 @@
         SCC_Result = may_modify_trail
     ).
 
+:- func combine_individual_proc_statuses(proc_results) = analysis_status.
+
+combine_individual_proc_statuses(ProcResults) =
+    list.foldl((func(proc_result(_, _, Status), Acc)
+            = analysis.lub(Status, Acc)),
+        ProcResults, optimal).
+
 %----------------------------------------------------------------------------%
 %
 % Perform trail usage analysis on a procedure
 % 
 
-:- pred check_proc_for_trail_mods(scc::in, module_info::in,
-    pred_proc_id::in, proc_results::in, proc_results::out) is det.
+:- pred check_proc_for_trail_mods(scc::in,
+    pred_proc_id::in, proc_results::in, proc_results::out,
+    module_info::in, module_info::out, io::di, io::uo) is det.
 
-check_proc_for_trail_mods(SCC, ModuleInfo, PPId, !Results) :-
-    module_info_pred_proc_info(ModuleInfo, PPId, _, ProcInfo),
+check_proc_for_trail_mods(SCC, PPId, !Results, !ModuleInfo, !IO) :-
+    module_info_pred_proc_info(!.ModuleInfo, PPId, _, ProcInfo),
     proc_info_goal(ProcInfo, Body),
     proc_info_vartypes(ProcInfo, VarTypes),
-    check_goal_for_trail_mods(SCC, ModuleInfo, VarTypes, Body, Result),
-    list.cons(proc_result(PPId, Result), !Results).
+    check_goal_for_trail_mods(SCC, VarTypes, Body, Result, AnalysisStatus,
+        !ModuleInfo, !IO),
+    list.cons(proc_result(PPId, Result, AnalysisStatus), !Results).
 
 %----------------------------------------------------------------------------%
 %
 % Perform trail usage analysis of a goal
 %
 
-:- pred check_goal_for_trail_mods(scc::in, module_info::in, vartypes::in,
-    hlds_goal::in, trailing_status::out) is det.  
-
-check_goal_for_trail_mods(SCC, ModuleInfo, VarTypes, Goal - GoalInfo,
-        Result) :-
-    check_goal_for_trail_mods_2(SCC, ModuleInfo, VarTypes, Goal, GoalInfo,
-        Result).
-
-:- pred check_goal_for_trail_mods_2(scc::in, module_info::in, vartypes::in,
-    hlds_goal_expr::in, hlds_goal_info::in, trailing_status::out) is det.
+:- pred check_goal_for_trail_mods(scc::in, vartypes::in, hlds_goal::in,
+    trailing_status::out, analysis_status::out,
+    module_info::in, module_info::out, io::di, io::uo) is det.  
+
+check_goal_for_trail_mods(SCC, VarTypes, Goal - GoalInfo,
+        Result, Status, !ModuleInfo, !IO) :-
+    check_goal_for_trail_mods_2(SCC, VarTypes, Goal, GoalInfo,
+        Result, Status, !ModuleInfo, !IO).
+
+:- pred check_goal_for_trail_mods_2(scc::in,
+    vartypes::in, hlds_goal_expr::in, hlds_goal_info::in, trailing_status::out, 
+    analysis_status::out, module_info::in, module_info::out, io::di, io::uo)
+    is det.
 
-check_goal_for_trail_mods_2(_, _, _, Goal, _, will_not_modify_trail) :-
+check_goal_for_trail_mods_2(_, _, Goal, _, will_not_modify_trail, optimal,
+        !ModuleInfo, !IO) :-
     Goal = unify(_, _, _, Kind, _),
     ( Kind = complicated_unify(_, _, _) ->
         unexpected(this_file, "complicated unify during trail usage analysis.")
     ;
         true
     ).
-check_goal_for_trail_mods_2(SCC, ModuleInfo, VarTypes, Goal, _, Result) :-
+check_goal_for_trail_mods_2(SCC, VarTypes, Goal, _, Result, AnalysisStatus,
+        !ModuleInfo, !IO) :-
     Goal = call(CallPredId, CallProcId, CallArgs, _, _, _),
     CallPPId = proc(CallPredId, CallProcId),    
-    module_info_pred_info(ModuleInfo, CallPredId, CallPredInfo),
+    module_info_pred_info(!.ModuleInfo, CallPredId, CallPredInfo),
     (
         % Handle (mutually-)recursive calls.
         list.member(CallPPId, SCC) 
     ->
         Types = list.map((func(Var) = VarTypes ^ det_elem(Var)), CallArgs),
-        TrailingStatus = check_types(ModuleInfo, Types),
-        Result = TrailingStatus
+        TrailingStatus = check_types(!.ModuleInfo, Types),
+        Result = TrailingStatus,
+        AnalysisStatus = optimal
     ; 
         pred_info_is_builtin(CallPredInfo) 
     ->
         % There are no builtins that will modify the trail.
-        Result = will_not_modify_trail
+        Result = will_not_modify_trail,
+        AnalysisStatus = optimal
     ;
         % Handle builtin unify and compare.
         % NOTE: the type specific unify and compare predicates are just
@@ -299,61 +340,82 @@
     ->
         % XXX We should examine the argument types of calls to builtin.unify/2
         % and builtin.compare/3 and then make a decision based on those.
-        Result = may_modify_trail
+        Result = may_modify_trail,
+        AnalysisStatus = optimal
     ;
         % Handle library predicates whose trailing status
         % can be looked up in the known procedures table.
         pred_info_has_known_status(CallPredInfo, Result0)
     ->
-        Result = Result0
+        Result = Result0,
+        AnalysisStatus = optimal
     ;
-        check_call(ModuleInfo, VarTypes, CallPPId, CallArgs, Result)
+        check_call_2(!.ModuleInfo, VarTypes, CallPPId, CallArgs, MaybeResult),
+        (
+            MaybeResult = yes({Result, AnalysisStatus})
+        ;
+            MaybeResult = no,
+            search_analysis_status(CallPPId, Result, AnalysisStatus, SCC,
+                !ModuleInfo, !IO)
+        )
     ).
-check_goal_for_trail_mods_2(_, _ModuleInfo, _VarTypes, Goal, _GoalInfo,
-        Result) :-
+
+check_goal_for_trail_mods_2(_, _VarTypes, Goal, _GoalInfo,
+        Result, AnalysisStatus, !ModuleInfo, !IO) :-
     Goal = generic_call(Details, _Args, _ArgModes, _),
     (
         % XXX Use results of closure analysis to handle this.
         Details = higher_order(_Var, _, _,  _),
-        Result = may_modify_trail
+        Result = may_modify_trail,
+        AnalysisStatus = optimal
     ;
         % XXX We could do better with class methods.
         Details = class_method(_, _, _, _),
-        Result = may_modify_trail
+        Result = may_modify_trail,
+        AnalysisStatus = optimal
     ;
         Details = cast(_),
-        Result  = will_not_modify_trail
+        Result  = will_not_modify_trail,
+        AnalysisStatus = optimal
     ;
         % XXX I'm not sure what the correct thing to do for 
         % aditi builtins is.
         Details = aditi_builtin(_, _),
-        Result = may_modify_trail
+        Result = may_modify_trail,
+        AnalysisStatus = optimal
     ).
-check_goal_for_trail_mods_2(SCC, ModuleInfo, VarTypes, not(Goal), _,
-        Result) :-
-    check_goal_for_trail_mods(SCC, ModuleInfo, VarTypes, Goal, Result).
-check_goal_for_trail_mods_2(SCC, ModuleInfo, VarTypes, Goal, OuterGoalInfo,
-        Result) :-
+check_goal_for_trail_mods_2(SCC, VarTypes, not(Goal), _,
+        Result, AnalysisStatus, !ModuleInfo, !IO) :-
+    check_goal_for_trail_mods(SCC, VarTypes, Goal, Result, AnalysisStatus,
+        !ModuleInfo, !IO).
+check_goal_for_trail_mods_2(SCC, VarTypes, Goal, OuterGoalInfo,
+        Result, AnalysisStatus, !ModuleInfo, !IO) :-
     Goal = scope(_, InnerGoal),
-    check_goal_for_trail_mods(SCC, ModuleInfo, VarTypes, InnerGoal, Result0),
+    check_goal_for_trail_mods(SCC, VarTypes, InnerGoal, Result0,
+        AnalysisStatus, !ModuleInfo, !IO),
     InnerGoal = _ - InnerGoalInfo,
     goal_info_get_code_model(InnerGoalInfo, InnerCodeModel),
     goal_info_get_code_model(OuterGoalInfo, OuterCodeModel),
     Result = scope_implies_trail_mod(InnerCodeModel, OuterCodeModel, Result0).
-check_goal_for_trail_mods_2(_, _, _, Goal, _, Result) :-
+check_goal_for_trail_mods_2(_, _, Goal, _, Result, AnalysisStatus,
+        !ModuleInfo, !IO) :-
     Goal = foreign_proc(Attributes, _, _, _, _, _),
-    Result = attributes_imply_trail_mod(Attributes).
-check_goal_for_trail_mods_2(_, _, _, shorthand(_), _, _) :-
+    Result = attributes_imply_trail_mod(Attributes),
+    AnalysisStatus = optimal.
+check_goal_for_trail_mods_2(_, _, shorthand(_), _, _, _, !ModuleInfo, !IO) :-
     unexpected(this_file,
         "shorthand goal encountered during trail usage analysis.").
-check_goal_for_trail_mods_2(SCC, ModuleInfo, VarTypes, Goal, _, Result) :-
+check_goal_for_trail_mods_2(SCC, VarTypes, Goal, _, Result, AnalysisStatus,
+        !ModuleInfo, !IO) :-
     Goal = switch(_, _, Cases),
     CaseGoals = list.map((func(case(_, CaseGoal)) = CaseGoal), Cases),
-    check_goals_for_trail_mods(SCC, ModuleInfo, VarTypes, CaseGoals, Result).
-check_goal_for_trail_mods_2(SCC, ModuleInfo, VarTypes, Goal, _, Result) :-
+    check_goals_for_trail_mods(SCC, VarTypes, CaseGoals, Result, AnalysisStatus,
+        !ModuleInfo, !IO).
+check_goal_for_trail_mods_2(SCC, VarTypes, Goal, _, Result, AnalysisStatus,
+        !ModuleInfo, !IO) :-
     Goal = if_then_else(_, If, Then, Else),
-    check_goals_for_trail_mods(SCC, ModuleInfo, VarTypes, [If, Then, Else],
-        Result0),
+    check_goals_for_trail_mods(SCC, VarTypes, [If, Then, Else],
+        Result0, AnalysisStatus, !ModuleInfo, !IO),
     (
         % If none of the disjuncts can modify the trail then we don't need
         % to emit trailing code around this disjunction.
@@ -363,15 +425,18 @@
         ( Result0 = conditional ; Result0 = may_modify_trail),
         Result = may_modify_trail
     ).
-check_goal_for_trail_mods_2(SCC, ModuleInfo, VarTypes, conj(Goals), _,
-        Result) :-
-    check_goals_for_trail_mods(SCC, ModuleInfo, VarTypes, Goals, Result).
-check_goal_for_trail_mods_2(SCC, ModuleInfo, VarTypes, par_conj(Goals), _,
-        Result) :-
-    check_goals_for_trail_mods(SCC, ModuleInfo, VarTypes, Goals, Result).
-check_goal_for_trail_mods_2(SCC, ModuleInfo, VarTypes, disj(Goals), _,
-        Result) :-
-    check_goals_for_trail_mods(SCC, ModuleInfo, VarTypes, Goals, Result0),
+check_goal_for_trail_mods_2(SCC, VarTypes, conj(Goals), _,
+        Result, AnalysisStatus, !ModuleInfo, !IO) :-
+    check_goals_for_trail_mods(SCC, VarTypes, Goals, Result, AnalysisStatus,
+        !ModuleInfo, !IO).
+check_goal_for_trail_mods_2(SCC, VarTypes, par_conj(Goals), _,
+        Result, AnalysisStatus, !ModuleInfo, !IO) :-
+    check_goals_for_trail_mods(SCC, VarTypes, Goals, Result, AnalysisStatus,
+        !ModuleInfo, !IO).
+check_goal_for_trail_mods_2(SCC, VarTypes, disj(Goals), _,
+        Result, AnalysisStatus, !ModuleInfo, !IO) :-
+    check_goals_for_trail_mods(SCC, VarTypes, Goals, Result0, AnalysisStatus,
+        !ModuleInfo, !IO),
     (
         % If none of the disjuncts can modify the trail then we don't need
         % to emit trailing code around this disjunction.
@@ -385,14 +450,17 @@
         Result = may_modify_trail
     ).
 
-:- pred check_goals_for_trail_mods(scc::in, module_info::in, vartypes::in,
-    hlds_goals::in, trailing_status::out) is det.
+:- pred check_goals_for_trail_mods(scc::in, vartypes::in,
+    hlds_goals::in, trailing_status::out, analysis_status::out,
+    module_info::in, module_info::out, io::di, io::uo) is det.
 
-check_goals_for_trail_mods(SCC, ModuleInfo, VarTypes, Goals, Result) :-
-    list.map(check_goal_for_trail_mods(SCC, ModuleInfo, VarTypes), Goals,
-        Results),
+check_goals_for_trail_mods(SCC, VarTypes, Goals, Result, AnalysisStatus,
+        !ModuleInfo, !IO) :-
+    list.map2_foldl2(check_goal_for_trail_mods(SCC, VarTypes), Goals,
+        Results, AnalysisStatuses, !ModuleInfo, !IO),
     list.foldl(combine_trailing_status, Results, will_not_modify_trail,
-        Result).
+        Result),
+    AnalysisStatus = list.foldl(analysis.lub, AnalysisStatuses, optimal).
 
 %----------------------------------------------------------------------------%
 %
@@ -483,7 +551,7 @@
     list(pred_proc_id)::in, list(pred_proc_id)::out) is semidet.
 
 get_conditional_closure(TrailingInfo, PPId, !Conditionals) :-
-    TrailingInfo ^ elem(PPId) = Status,
+    TrailingInfo ^ elem(PPId) = {Status, _},
     (
         Status = conditional,
         list.cons(PPId, !Conditionals)
@@ -513,27 +581,41 @@
     pred_proc_id::in, prog_vars::in, trailing_status::out) is det.
 
 check_call(ModuleInfo, VarTypes, PPId, Args, Result) :-
+    check_call_2(ModuleInfo, VarTypes, PPId, Args, MaybeResult),
+    (
+        MaybeResult = yes({Result, _})
+    ;
+        MaybeResult = no,
+        % If we do not have any information about the callee procedure then
+        % assume that it modifies the trail.
+        Result = may_modify_trail
+    ).
+
+:- pred check_call_2(module_info::in, vartypes::in,
+    pred_proc_id::in, prog_vars::in,
+    maybe({trailing_status, analysis_status})::out) is det.
+
+check_call_2(ModuleInfo, VarTypes, PPId, Args, MaybeResult) :-
     module_info_get_trailing_info(ModuleInfo, TrailingInfo),
     ( map.search(TrailingInfo, PPId, CalleeTrailingStatus) ->
         (
-            CalleeTrailingStatus = will_not_modify_trail,
-            Result = will_not_modify_trail
+            CalleeTrailingStatus = {will_not_modify_trail, _},
+            MaybeResult = yes(CalleeTrailingStatus)
         ;
-            CalleeTrailingStatus = may_modify_trail,
-            Result = may_modify_trail
+            CalleeTrailingStatus = {may_modify_trail, _},
+            MaybeResult = yes(CalleeTrailingStatus)
         ;
-            CalleeTrailingStatus = conditional,
+            CalleeTrailingStatus = {conditional, AnalysisStatus},
             %
             % This is a call to a polymorphic procedure.  We need to make
             % sure that none of the types involved has a user-defined
             % equality or comparison predicate that modifies the trail.
             % XXX Need to handle higher-order args here as well.
-            Result = check_vars(ModuleInfo, VarTypes, Args) 
+            MaybeResult = yes({TrailingStatus, AnalysisStatus}),
+            TrailingStatus = check_vars(ModuleInfo, VarTypes, Args)
         )
     ;
-        % If we do not have any information about the callee procedure then
-        % assume that it modifies the trail.
-        Result = may_modify_trail
+        MaybeResult = no
     ).
 
 :- func check_vars(module_info, vartypes, prog_vars) = trailing_status.
@@ -864,7 +946,7 @@
         list.foldl((pred(ProcId::in, !.IO::di, !:IO::uo) is det :-
             proc_id_to_int(ProcId, ModeNum),
             ( 
-                map.search(TrailingInfo, proc(PredId, ProcId), Status)
+                map.search(TrailingInfo, proc(PredId, ProcId), {Status, _})
             ->
                 mercury_output_pragma_trailing_info(PredOrFunc, 
                     qualified(ModuleName, Name), Arity,
@@ -876,6 +958,166 @@
         true
     ).          
 
+%-----------------------------------------------------------------------------%
+%
+% Stuff for the intermodule analysis framework
+%
+
+:- type trailing_analysis_answer
+    --->    trailing_analysis_answer(trailing_status).
+
+:- func analysis_name = string.
+analysis_name = "trailing_info".  % same name as used for the pragmas
+
+:- instance analysis(any_call, trailing_analysis_answer) where [
+    analysis_name(_, _) = analysis_name,
+    analysis_version_number(_, _) = 1,
+    preferred_fixpoint_type(_, _) = least_fixpoint,
+                                    % XXX: I have no idea if this is correct.
+    bottom(_) = trailing_analysis_answer(will_not_modify_trail),
+    top(_) = trailing_analysis_answer(may_modify_trail)
+].
+
+:- instance answer_pattern(trailing_analysis_answer) where [].
+:- instance partial_order(trailing_analysis_answer) where [
+    (more_precise_than(
+            trailing_analysis_answer(Status1),
+            trailing_analysis_answer(Status2)) :-
+        trailing_status_more_precise_than(Status1, Status2)),
+    equivalent(Status, Status)
+].
+
+:- pred trailing_status_more_precise_than(trailing_status::in,
+        trailing_status::in) is semidet.
+
+trailing_status_more_precise_than(will_not_modify_trail, may_modify_trail).
+trailing_status_more_precise_than(will_not_modify_trail, conditional).
+trailing_status_more_precise_than(conditional, may_modify_trail).
+
+:- instance to_string(trailing_analysis_answer) where [
+    func(to_string/1) is trailing_analysis_answer_to_string,
+    func(from_string/1) is trailing_analysis_answer_from_string
+].
+
+:- func trailing_analysis_answer_to_string(trailing_analysis_answer) = string.
+
+trailing_analysis_answer_to_string(trailing_analysis_answer(Status)) = Str :-
+    trailing_status_to_string(Status, Str).
+
+:- func trailing_analysis_answer_from_string(string) =
+        trailing_analysis_answer is semidet.
+
+trailing_analysis_answer_from_string(Str) = trailing_analysis_answer(Status) :-
+    trailing_status_to_string(Status, Str).
+
+:- pred trailing_status_to_string(trailing_status, string).
+:- mode trailing_status_to_string(in, out) is det.
+:- mode trailing_status_to_string(out, in) is semidet.
+
+trailing_status_to_string(may_modify_trail, "may_modify_trail").
+trailing_status_to_string(will_not_modify_trail, "will_not_modify_trail").
+trailing_status_to_string(conditional, "conditional").
+
+:- pred search_analysis_status(pred_proc_id::in,
+        trailing_status::out, analysis_status::out, scc::in,
+        module_info::in, module_info::out, io::di, io::uo) is det.
+
+search_analysis_status(PPId, Result, AnalysisStatus, CallerSCC,
+        !ModuleInfo, !IO) :-
+    globals__io_lookup_bool_option(intermodule_analysis, Intermod, !IO),
+    (
+        Intermod = yes,
+        module_info_get_analysis_info(!.ModuleInfo, AnalysisInfo0),
+        search_analysis_status_2(!.ModuleInfo, PPId, Result, AnalysisStatus,
+            CallerSCC, AnalysisInfo0, AnalysisInfo, !IO),
+        module_info_set_analysis_info(AnalysisInfo, !ModuleInfo)
+    ;
+        Intermod = no,
+        % If we do not have any information about the callee procedure
+        % then assume that it modifies the trail.
+        Result = may_modify_trail,
+        AnalysisStatus = optimal    % unused anyway
+    ).
+
+:- pred search_analysis_status_2(module_info::in, pred_proc_id::in,
+        trailing_status::out, analysis_status::out, scc::in,
+        analysis_info::in, analysis_info::out, io::di, io::uo) is det.
+
+search_analysis_status_2(ModuleInfo, PPId, Result, AnalysisStatus, CallerSCC,
+        !AnalysisInfo, !IO) :-
+    module_id_func_id(ModuleInfo, PPId, ModuleId, FuncId),
+    Call = any_call,
+    analysis.lookup_best_result(ModuleId, FuncId, Call,
+        MaybeBestStatus, !AnalysisInfo, !IO),
+    (
+        MaybeBestStatus = yes({BestCall, trailing_analysis_answer(Result),
+            AnalysisStatus}),
+        record_dependencies(analysis_name, ModuleId, FuncId, BestCall,
+            ModuleInfo, CallerSCC, !AnalysisInfo)
+    ;
+        MaybeBestStatus = no,
+        % If we do not have any information about the callee procedure
+        % then assume that it modifies the trail.
+        top(Call) = trailing_analysis_answer(Result),
+        AnalysisStatus = suboptimal,
+        analysis.record_request(analysis_name, ModuleId, FuncId, Call,
+            !AnalysisInfo),
+        record_dependencies(analysis_name, ModuleId, FuncId, Call,
+            ModuleInfo, CallerSCC, !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(analysis_name::in, module_id::in, func_id::in,
+	Call::in, module_info::in, scc::in,
+	analysis_info::in, analysis_info::out) is det
+	<= call_pattern(Call).
+
+record_dependencies(AnalysisName, ModuleId, FuncId, Call,
+        ModuleInfo, CallerSCC, !AnalysisInfo) :-
+    list.foldl((pred(CallerPPId::in, Info0::in, Info::out) is det :-
+        module_id_func_id(ModuleInfo, CallerPPId, CallerModuleId, _),
+        analysis.record_dependency(CallerModuleId,
+            AnalysisName, ModuleId, 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,
+        analysis_info::in, analysis_info::out) is det.
+
+record_trailing_analysis_result(ModuleInfo, Status, ResultStatus, PPId,
+        AnalysisInfo0, AnalysisInfo) :-
+    module_id_func_id(ModuleInfo, PPId, ModuleId, FuncId),
+    record_result(ModuleId, FuncId, any_call,
+        trailing_analysis_answer(Status), ResultStatus,
+        AnalysisInfo0, AnalysisInfo).
+
+:- pred module_id_func_id(module_info::in, pred_proc_id::in,
+        module_id::out, func_id::out) is det.
+
+module_id_func_id(ModuleInfo, proc(PredId, ProcId), ModuleId, FuncId) :-
+    module_info_pred_info(ModuleInfo, PredId, PredInfo),
+    PredModule = pred_info_module(PredInfo),
+    PredName = pred_info_name(PredInfo),
+    PredOrFunc = pred_info_is_pred_or_func(PredInfo),
+    PredArity = pred_info_orig_arity(PredInfo),
+    ModuleId = module_name_to_module_id(PredModule),
+    FuncId = pred_or_func_name_arity_to_func_id(PredOrFunc,
+        PredName, PredArity, ProcId).
+
 %----------------------------------------------------------------------------%
 %
 % Code for printing out debugging traces
Index: compiler/unused_args.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/unused_args.m,v
retrieving revision 1.116
diff -u -r1.116 unused_args.m
--- compiler/unused_args.m	4 Jan 2006 07:14:31 -0000	1.116
+++ compiler/unused_args.m	10 Jan 2006 04:35:38 -0000
@@ -62,13 +62,14 @@
 % Instances used by mmc_analysis.m
 %
 
+:- type unused_args_call.
 :- type unused_args_answer.
-:- type unused_args_func_info.
-:- instance analysis(unused_args_func_info, any_call, unused_args_answer).
-:- instance partial_order(unused_args_func_info, any_call).
-:- instance call_pattern(unused_args_func_info, any_call).
-:- instance partial_order(unused_args_func_info, unused_args_answer).
-:- instance answer_pattern(unused_args_func_info, unused_args_answer).
+:- instance analysis(unused_args_call, unused_args_answer).
+:- instance partial_order(unused_args_call).
+:- instance call_pattern(unused_args_call).
+:- instance to_string(unused_args_call).
+:- instance partial_order(unused_args_answer).
+:- instance answer_pattern(unused_args_answer).
 :- instance to_string(unused_args_answer).
 
 %-----------------------------------------------------------------------------%
@@ -143,6 +144,11 @@
 % Types and instances used by mmc_analysis.m
 %
 
+:- type unused_args_call
+    --->    unused_args_call(arity).
+            % Stands for any call.  The arity is extra information which is
+            % not part of the call pattern.
+
     % The list of unused arguments is in sorted order.
 :- type unused_args_answer
     --->    unused_args(
@@ -153,30 +159,45 @@
 
 get_unused_args(UnusedArgs) = UnusedArgs ^ args.
 
-:- instance analysis(unused_args_func_info, any_call, unused_args_answer)
+:- instance analysis(unused_args_call, unused_args_answer)
         where [
-    analysis_name(_, _, _) = "unused_args",
-    analysis_version_number(_, _, _) = 1,
-    preferred_fixpoint_type(_, _, _) = least_fixpoint
+    analysis_name(_, _) = analysis_name,
+    analysis_version_number(_, _) = 2,
+    preferred_fixpoint_type(_, _) = least_fixpoint,
+    bottom(unused_args_call(Arity)) = unused_args(1 `..` Arity),
+    top(_) = unused_args([])
 ].
 
-:- type unused_args_func_info ---> unused_args_func_info(arity).
+:- func analysis_name = string.
+analysis_name = "unused_args".
 
-:- instance call_pattern(unused_args_func_info, any_call) where [].
-:- instance partial_order(unused_args_func_info, any_call) where [
-    (more_precise_than(_, _, _) :- semidet_fail),
-    (equivalent(_, _, _) :- semidet_succeed)
+:- instance call_pattern(unused_args_call) where [].
+:- instance partial_order(unused_args_call) where [
+    (more_precise_than(_, _) :- semidet_fail),
+    equivalent(Call, Call)
 ].
 
-:- instance answer_pattern(unused_args_func_info, unused_args_answer) where [
-    bottom(unused_args_func_info(Arity)) = unused_args(1 `..` Arity),
-    top(_) = unused_args([])
+:- instance to_string(unused_args_call) where [
+    func(to_string/1) is unused_args_call_to_string,
+    func(from_string/1) is unused_args_call_from_string
 ].
-:- instance partial_order(unused_args_func_info, unused_args_answer) where [
-    (more_precise_than(_, unused_args(Args1), unused_args(Args2)) :-
+
+:- func unused_args_call_to_string(unused_args_call) = string.
+
+unused_args_call_to_string(unused_args_call(Arity)) =
+    string.from_int(Arity).
+
+:- func unused_args_call_from_string(string) = unused_args_call is semidet.
+
+unused_args_call_from_string(String) = unused_args_call(Arity) :-
+    string.to_int(String, Arity).
+
+:- instance answer_pattern(unused_args_answer) where [].
+:- instance partial_order(unused_args_answer) where [
+    (more_precise_than(unused_args(Args1), unused_args(Args2)) :-
         set__subset(sorted_list_to_set(Args2), sorted_list_to_set(Args1))
     ),
-    equivalent(_, Args, Args)
+    equivalent(Args, Args)
 ].
 
 :- instance to_string(unused_args_answer) where [
@@ -370,33 +391,46 @@
             pred_info_is_imported(PredInfo)
         ->
             PredModule = pred_info_module(PredInfo),
+            PredModuleId = module_name_to_module_id(PredModule),
             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),
+            Call = unused_args_call(PredArity),
             module_info_get_analysis_info(!.ModuleInfo, AnalysisInfo0),
-            lookup_best_result(module_name_to_module_id(PredModule),
-                FuncId, unused_args_func_info(PredArity),
-                any_call, MaybeBestResult, AnalysisInfo0, AnalysisInfo, !IO),
-            module_info_set_analysis_info(AnalysisInfo, !ModuleInfo),
-            ( MaybeBestResult = yes(_ - unused_args(UnusedArgs)) ->
-                proc_info_headvars(ProcInfo, HeadVars),
-                list__map(list__index1_det(HeadVars), UnusedArgs, UnusedVars),
-                initialise_vardep(UnusedVars, !.VarDep, VarDep),
-                svmap__set(proc(PredId, ProcId), VarDep, !VarUsage),
-                globals__io_lookup_bool_option(optimize_unused_args, Optimize,
-                    !IO),
-                (
-                    Optimize = yes,
-                    make_imported_unused_args_pred_info(proc(PredId, ProcId),
-                        UnusedArgs, !OptProcs, !ModuleInfo)
+            lookup_best_result(PredModuleId, FuncId, Call,
+                MaybeBestResult, AnalysisInfo0, AnalysisInfo1, !IO),
+            (
+                MaybeBestResult = yes({_, unused_args(UnusedArgs), _}),
+                ( UnusedArgs \= [] ->
+                    proc_info_headvars(ProcInfo, HeadVars),
+                    list__map(list__index1_det(HeadVars), UnusedArgs, UnusedVars),
+                    initialise_vardep(UnusedVars, !.VarDep, VarDep),
+                    svmap__set(proc(PredId, ProcId), VarDep, !VarUsage),
+                    globals__io_lookup_bool_option(optimize_unused_args, Optimize,
+                        !IO),
+                    (
+                        Optimize = yes,
+                        make_imported_unused_args_pred_info(proc(PredId, ProcId),
+                            UnusedArgs, !OptProcs, !ModuleInfo)
+                    ;
+                        Optimize = no
+                    )
                 ;
-                    Optimize = no
-                )
+                    true
+                ),
+                module_info_get_name(!.ModuleInfo, CallerModule),
+                CallerModuleId = module_name_to_module_id(CallerModule),
+                analysis.record_dependency(CallerModuleId,
+                    analysis_name, PredModuleId, FuncId, Call,
+                    AnalysisInfo1, AnalysisInfo)
             ;
-                true
-            )
+                MaybeBestResult = no,
+                analysis.record_request(analysis_name, PredModuleId, 
+                    FuncId, Call, AnalysisInfo1, AnalysisInfo)
+            ),
+            module_info_set_analysis_info(AnalysisInfo, !ModuleInfo)
         ;
             (
                 pred_info_is_imported(PredInfo)
@@ -914,63 +948,56 @@
     map__lookup(UnusedArgInfo, proc(PredId, ProcId), UnusedArgs),
     module_info_pred_proc_info(!.ModuleInfo, PredId, ProcId,
         OrigPredInfo, OrigProcInfo),
+    PredModule = pred_info_module(OrigPredInfo),
+    PredName = pred_info_name(OrigPredInfo),
+
+    globals__io_lookup_bool_option(intermodule_analysis, Intermod, !IO),
+    (
+        Intermod = yes,
+        module_info_get_analysis_info(!.ModuleInfo, AnalysisInfo0),
+        PredOrFunc = pred_info_is_pred_or_func(OrigPredInfo),
+        PredArity = pred_info_orig_arity(OrigPredInfo),
+        ModuleId = module_name_to_module_id(PredModule),
+        FuncId = pred_or_func_name_arity_to_func_id(PredOrFunc,
+            PredName, PredArity, ProcId),
+        Call = unused_args_call(PredArity),
+        Answer = unused_args(UnusedArgs),
+
+        analysis.lookup_results(ModuleId, FuncId,
+            IntermodResultsTriples : list({unused_args_call,
+                unused_args_answer, analysis_status}),
+            AnalysisInfo0, AnalysisInfo1, !IO),
+        IntermodOldAnswers = list__map((func({_, Ans, _}) = Ans),
+            IntermodResultsTriples),
+        FilterUnused = (pred(VersionAnswer::in) is semidet :-
+            VersionAnswer \= Answer,
+            VersionAnswer \= unused_args([]),
+            Answer `more_precise_than` 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.
+        analysis__record_result(ModuleId, FuncId, Call, Answer, optimal,
+            AnalysisInfo1, AnalysisInfo),
+        module_info_set_analysis_info(AnalysisInfo, !ModuleInfo)
+    ;
+        Intermod = no,
+        IntermodResultsTriples = [],
+        IntermodOldArgLists = []
+    ),
+
     (
         UnusedArgs = []
     ;
         UnusedArgs = [_ | _],
-        PredModule = pred_info_module(OrigPredInfo),
-        PredName = pred_info_name(OrigPredInfo),
-
-        globals__io_lookup_bool_option(intermodule_analysis, Intermod, !IO),
-        (
-            Intermod = yes,
-            module_info_get_analysis_info(!.ModuleInfo, AnalysisInfo0),
-            PredOrFunc = pred_info_is_pred_or_func(OrigPredInfo),
-            PredArity = pred_info_orig_arity(OrigPredInfo),
-            ModuleId = module_name_to_module_id(PredModule),
-            FuncId = pred_or_func_name_arity_to_func_id(PredOrFunc,
-                PredName, PredArity, ProcId),
-            FuncInfo = unused_args_func_info(PredArity),
-
-            lookup_results(ModuleId, FuncId, FuncInfo,
-                IntermodResultsPairs `with_type`
-                    assoc_list(any_call, unused_args_answer),
-                AnalysisInfo0, AnalysisInfo1, !IO),
-            IntermodResultsArgsLists = list__map(get_unused_args,
-                assoc_list__values(IntermodResultsPairs)),
-            ( list__member(UnusedArgs, IntermodResultsArgsLists) ->
-                AnalysisInfo = AnalysisInfo1
-            ;
-                analysis__record_result(ModuleId, FuncId, FuncInfo, any_call,
-                    unused_args(UnusedArgs), AnalysisInfo1, AnalysisInfo)
-            ),
-            module_info_set_analysis_info(AnalysisInfo, !ModuleInfo),
-
-            %
-            % XXX Mark versions which have more unused arguments
-            % than what we have computed here as invalid
-            % in the AnalysisInfo, so that modules which use
-            % those versions can be recompiled.
-            %
-            FilterUnused = (pred(VersionUnused::in) is semidet :-
-                VersionUnused \= UnusedArgs,
-                set__subset(
-                    sorted_list_to_set(VersionUnused),
-                    sorted_list_to_set(UnusedArgs)
-                )
-            ),
-            IntermodResults = list__filter(FilterUnused,
-                IntermodResultsArgsLists)
-        ;
-            Intermod = no,
-            IntermodResultsPairs = [],
-            IntermodResults = []
-        ),
         pred_info_import_status(OrigPredInfo, Status0),
         (
             Status0 = opt_imported,
-            IntermodResultsPairs = [_ | _],
-            IntermodResults = []
+            IntermodResultsTriples = [_ | _],
+            IntermodOldArgLists = []
         ->
             % If this predicate is from a .opt file, and no more arguments
             % have been removed than in the original module, then leave the
@@ -1015,10 +1042,15 @@
 
         % Add forwarding predicates for results produced in previous
         % compilations.
+        % XXX this only works "once" due to the analysis framework now
+        % discarding all but the best answer.  If we compile this module
+        % again without changing anything else, we won't remember to
+        % produce the same forwarding predicates.  If some callers refer
+        % to those forwarding predicates then linking will fail.
         list__foldl(
             make_intermod_proc(PredId, NewPredId, ProcId, NewPredName,
                 OrigPredInfo, OrigProcInfo, UnusedArgs),
-            IntermodResults, !ModuleInfo)
+            IntermodOldArgLists, !ModuleInfo)
     ).
 
 :- pred make_intermod_proc(pred_id::in, pred_id::in, proc_id::in, string::in,
Index: library/list.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/list.m,v
retrieving revision 1.143
diff -u -r1.143 list.m
--- library/list.m	15 Nov 2005 04:59:23 -0000	1.143
+++ library/list.m	19 Dec 2005 00:34:52 -0000
@@ -845,6 +845,24 @@
 :- mode list__map_foldl2(pred(in, out, in, out, in, out) is nondet,
     in, out, in, out, in, out) is nondet.
 
+    % Same as list__map_foldl, but with two mapped outputs and two
+    % accumulators.
+    %
+:- pred list__map2_foldl2(pred(L, M, N, A, A, B, B), list(L), list(M), list(N),
+    A, A, B, B).
+:- mode list__map2_foldl2(pred(in, out, out, in, out, di, uo) is det,
+    in, out, out, in, out, di, uo) is det.
+:- mode list__map2_foldl2(pred(in, out, out, in, out, in, out) is det,
+    in, out, out, in, out, in, out) is det.
+:- mode list__map2_foldl2(pred(in, out, out, in, out, di, uo) is cc_multi,
+    in, out, out, in, out, di, uo) is cc_multi.
+:- mode list__map2_foldl2(pred(in, out, out, in, out, in, out) is cc_multi,
+    in, out, out, in, out, in, out) is cc_multi.
+:- mode list__map2_foldl2(pred(in, out, out, in, out, in, out) is semidet,
+    in, out, out, in, out, in, out) is semidet.
+:- mode list__map2_foldl2(pred(in, out, out, in, out, in, out) is nondet,
+    in, out, out, in, out, in, out) is nondet.
+
     % Same as list__map_foldl, but with three accumulators.
     %
 :- pred list__map_foldl3(pred(L, M, A, A, B, B, C, C), list(L), list(M),
@@ -1817,6 +1835,11 @@
     call(P, H0, H, !A, !B),
     list__map_foldl2(P, T0, T, !A, !B).
 
+list__map2_foldl2(_, [], [], [], !A, !B).
+list__map2_foldl2(P, [H0 | T0], [H1 | T1], [H2 | T2], !A, !B) :-
+    call(P, H0, H1, H2, !A, !B),
+    list__map2_foldl2(P, T0, T1, T2, !A, !B).
+
 list__map_foldl3(_, [], [], !A, !B, !C).
 list__map_foldl3(P, [H0 | T0], [H | T], !A, !B, !C) :-
     call(P, H0, H, !A, !B, !C),
Index: compiler/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/Mmakefile,v
retrieving revision 1.87
diff -u -r1.87 Mmakefile
--- compiler/Mmakefile	16 Dec 2005 05:49:38 -0000	1.87
+++ compiler/Mmakefile	19 Dec 2005 00:44:45 -0000
@@ -273,8 +273,10 @@
 
 #-----------------------------------------------------------------------------#
 
-tags:	$(PREPROCESSED_M_FILES) *.m $(LIBRARY_DIR)/*.m $(MDBCOMP_DIR)/*.m
-	$(MTAGS) $(MTAGSFLAGS) *.m $(LIBRARY_DIR)/*.m $(MDBCOMP_DIR)/*.m
+tags:	$(PREPROCESSED_M_FILES) *.m $(LIBRARY_DIR)/*.m $(MDBCOMP_DIR)/*.m \
+		$(ANALYSIS_DIR)/*.m
+	$(MTAGS) $(MTAGSFLAGS) *.m $(LIBRARY_DIR)/*.m $(MDBCOMP_DIR)/*.m \
+		$(ANALYSIS_DIR)/*.m
 
 .PHONY: tags_file_exists
 tags_file_exists:
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list