[m-rev.] diff: add --debug-indirect-reuse option

Peter Wang novalazy at gmail.com
Mon Apr 28 17:23:22 AEST 2008


Branches: main

Add a `--debug-indirect-reuse' option which prints out at each call site
whether that call could be made to use a reuse version of the procedure.
If not, it prints out a reason why not.

compiler/options.m:
doc/user_guide.texi:
	Add the option.

compiler/ctgc.datastruct.m:
	Add a version of `datastructs_subsumed_by_list' which also returns the
	subsumed datastructs.

compiler/ctgc.livedata.m:
	Make `nodes_are_not_live' return the datastructs which we want to be
	dead but are still live.

compiler/structure_reuse.domain.m:
	Make `reuse_as_satisfied' and `reuse_condition_satisfied'
	return reasons for reuse conditions not being satisfied.

compiler/structure_reuse.indirect.m:
	Print out "% Indirect reuse analysis ..." etc. lines for
	`--debug-indirect-reuse'.  Get rid of progress dots for
	`--very-verbose'.

	Make `verify_indirect_reuse' print out its result and the reasoning.

	Don't thread I/O state through some predicates that don't need it.

Index: compiler/ctgc.datastruct.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/ctgc.datastruct.m,v
retrieving revision 1.11
diff -u -r1.11 ctgc.datastruct.m
--- compiler/ctgc.datastruct.m	23 Apr 2008 05:16:49 -0000	1.11
+++ compiler/ctgc.datastruct.m	28 Apr 2008 07:00:18 -0000
@@ -72,13 +72,19 @@
 
 :- pred datastruct_subsumed_by_return_selector(module_info::in, proc_info::in,
     datastruct::in, datastruct::in, selector::out) is semidet.
+
 :- pred datastruct_subsumed_by(module_info::in, proc_info::in,
     datastruct::in, datastruct::in) is semidet.
+
 :- pred datastruct_subsumed_by_list(module_info::in, proc_info::in,
     datastruct::in, list(datastruct)::in) is semidet.
+
 :- pred datastructs_subsumed_by_list(module_info::in, proc_info::in,
     list(datastruct)::in, list(datastruct)::in) is semidet.
 
+:- pred datastructs_that_are_subsumed_by_list(module_info::in, proc_info::in,
+    list(datastruct)::in, list(datastruct)::in, list(datastruct)::out) is det.
+
 :- func datastruct_lists_least_upper_bound(module_info, proc_info,
     list(datastruct), list(datastruct)) = list(datastruct).
 
@@ -88,6 +94,8 @@
 :- func datastructs_project(list(prog_var), 
     list(datastruct)) = list(datastruct).
 
+:- func datastructs_vars(list(datastruct)) = list(prog_var).
+
 %-----------------------------------------------------------------------------%
 
 :- implementation.
@@ -165,6 +173,12 @@
         datastructs_subsume_datastruct(ModuleInfo, ProcInfo, Data, X)
     ).
 
+datastructs_that_are_subsumed_by_list(ModuleInfo, ProcInfo,
+        PerhapsSubsumedData, Datastructs, SubsumedData) :-
+    list.filter(
+        datastructs_subsume_datastruct(ModuleInfo, ProcInfo, Datastructs),
+        PerhapsSubsumedData, SubsumedData).
+
 :- pred datastructs_subsume_datastruct(module_info::in, proc_info::in, 
     list(datastruct)::in, datastruct::in) is semidet.
 
@@ -191,6 +205,8 @@
         (pred(Data::in) is semidet :- list.member(Data ^ sc_var, Vars)),
         DataIn).
 
+datastructs_vars(Data) = list.map(func(X) = X ^ sc_var, Data).
+
 %-----------------------------------------------------------------------------%
 :- end_module transform_hlds.ctgc.datastruct.
 %-----------------------------------------------------------------------------%
Index: compiler/ctgc.livedata.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/ctgc.livedata.m,v
retrieving revision 1.5
diff -u -r1.5 ctgc.livedata.m
--- compiler/ctgc.livedata.m	23 Apr 2008 05:16:49 -0000	1.5
+++ compiler/ctgc.livedata.m	28 Apr 2008 07:00:18 -0000
@@ -75,8 +75,12 @@
 :- func livedata_add_liveness(module_info, proc_info, live_datastructs,
     sharing_as, livedata) = livedata.
 
-:- pred nodes_are_not_live(module_info::in, proc_info::in, 
-    list(datastruct)::in, livedata::in) is semidet.
+:- pred nodes_are_not_live(module_info::in, proc_info::in,
+    list(datastruct)::in, livedata::in, nodes_are_not_live_result::out) is det.
+
+:- type nodes_are_not_live_result
+    --->    nodes_all_live
+    ;       nodes_are_live(list(datastruct)).
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
@@ -85,6 +89,7 @@
 
 :- import_module libs.compiler_util.
 :- import_module transform_hlds.ctgc.datastruct.
+:- import_module transform_hlds.ctgc.structure_sharing.domain.
 
 :- import_module pair.
 :- import_module set.
@@ -339,7 +344,7 @@
             ), SelectorList, List_Xsx1)
 	).
 
-livedata_add_liveness(ModuleInfo, ProcInfo, LuData, LocalSharing, LiveData0) 
+livedata_add_liveness(ModuleInfo, ProcInfo, LuData, LocalSharing, LiveData0)
         = LiveData :- 
     ( 
         sharing_as_is_top(LocalSharing)
@@ -377,16 +382,18 @@
             SharingAs, Data0))
     ).
 
-nodes_are_not_live(ModuleInfo, ProcInfo, Nodes, LiveData) :- 
+nodes_are_not_live(ModuleInfo, ProcInfo, DeadNodes, LiveData, Result) :- 
     (
         LiveData = livedata_top,
-        fail
+        Result = nodes_all_live
     ; 
         LiveData = livedata_bottom,
-        true
+        Result = nodes_are_live([])
     ;
-        LiveData = livedata_live(Data),
-        \+ datastructs_subsumed_by_list(ModuleInfo, ProcInfo, Nodes, Data)
+        LiveData = livedata_live(LiveDatastructs),
+        datastructs_that_are_subsumed_by_list(ModuleInfo, ProcInfo,
+            DeadNodes, LiveDatastructs, SubsumedNodes),
+        Result = nodes_are_live(SubsumedNodes)
     ).
 
 %-----------------------------------------------------------------------------%
Index: compiler/options.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/options.m,v
retrieving revision 1.613
diff -u -r1.613 options.m
--- compiler/options.m	29 Jan 2008 02:38:26 -0000	1.613
+++ compiler/options.m	28 Apr 2008 07:00:21 -0000
@@ -158,6 +158,7 @@
     ;       debug_mode_constraints 
     ;       debug_intermodule_analysis
     ;       debug_mm_tabling_analysis
+    ;       debug_indirect_reuse
 
     % Output options
     ;       make_short_interface
@@ -1003,7 +1004,8 @@
     debug_trail_usage                   -   bool(no),
     debug_mode_constraints              -   bool(no),
     debug_intermodule_analysis          -   bool(no),
-    debug_mm_tabling_analysis           -   bool(no)
+    debug_mm_tabling_analysis           -   bool(no),
+    debug_indirect_reuse                -   bool(no)
 ]).
 option_defaults_2(output_option, [
     % Output Options (mutually exclusive)
@@ -1789,6 +1791,7 @@
 long_option("debug-mode-constraints", debug_mode_constraints).
 long_option("debug-intermodule-analysis",   debug_intermodule_analysis).
 long_option("debug-mm-tabling-analysis",    debug_mm_tabling_analysis).
+long_option("debug-indirect-reuse",         debug_indirect_reuse).
 
 % output options (mutually exclusive)
 long_option("generate-source-file-mapping", generate_source_file_mapping).
@@ -3255,7 +3258,10 @@
         "\toption.",
         "--debug-intermodule-analysis",
         "\tOutput detailed debugging traces of the `--intermodule-analysis'",
-        "\toption."
+        "\toption.",
+        "--debug-indirect-reuse",
+        "\tOutput detailed debugging traces of the indirect reuse pass of",
+        "\t`--structure-reuse' option."
 % The mode constraints code is still experimental so this option is
 % currently commented out.
 %         "--debug-mode-constraints",
Index: compiler/structure_reuse.domain.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/structure_reuse.domain.m,v
retrieving revision 1.13
diff -u -r1.13 structure_reuse.domain.m
--- compiler/structure_reuse.domain.m	23 Apr 2008 05:16:49 -0000	1.13
+++ compiler/structure_reuse.domain.m	28 Apr 2008 07:00:21 -0000
@@ -163,14 +163,34 @@
 :- func reuse_as_from_called_procedure_to_local_reuse_as(module_info,
     proc_info, prog_vars, live_datastructs, sharing_as, reuse_as) = reuse_as.
 
-
-    % Succeeds if taking into account the live data and static variables the
+    % Taking into account the live data and static variables, check if the
     % reuse conditions expressed by reuse_as are all satisfied, hence making
     % the associated memory reuses safe for that particular calling
-    % environment.
+    % environment. If the conditions are not satisfied, return the
+    % variables which caused one of the conditions to be violated.
     % 
 :- pred reuse_as_satisfied(module_info::in, proc_info::in, livedata::in,
-    sharing_as::in, prog_vars::in, reuse_as::in) is semidet.
+    sharing_as::in, prog_vars::in, reuse_as::in, reuse_satisfied_result::out)
+    is det.
+
+:- type reuse_satisfied_result
+    --->    reuse_possible
+    ;       reuse_not_possible(reuse_not_possible_reason).
+
+:- type reuse_not_possible_reason
+    --->    no_reuse
+            % No reuse version of the procedure.
+
+    ;       unknown_livedata
+            % We had to assume everything was live.
+
+    ;       reuse_condition_violated(list(prog_var))
+            % At least these variables couldn't be allowed to be clobbered.
+
+    ;       reuse_nodes_have_sharing.
+            % The reuse conditions are individually satisfied, but the
+            % arguments for reuse have sharing between them which would lead
+            % to undefined behaviour in the reuse version of the procedure.
 
     % Conversion procedures between the public (structure_reuse_domain) 
     % and private (reuse_as) representation for structure reuse conditions. 
@@ -284,17 +304,18 @@
     % case the condition is always satisfied, independent of any calling
     % environment.
     (
-        Nodes = []
-    ->
+        Nodes = [],
         Condition = always
     ;
+        Nodes = [_ | _],
         set.union(LFU, LBU, LU),
-            % XXX the old implementation did not bother about extending at
-            % this place, which was contrary to the theory. Check the effect
-            % of this change!
-        SharedLU = list.condense(
-            list.map(extend_datastruct(ModuleInfo, ProcInfo, Sharing),
-                list.map(datastruct_init, set.to_sorted_list(LU)))),
+        % XXX the old implementation did not bother about extending at this
+        % place, which was contrary to the theory. Check the effect of this
+        % change!
+        LuData = list.map(datastruct_init, set.to_sorted_list(LU)),
+        ExtendedLuData = list.map(
+            extend_datastruct(ModuleInfo, ProcInfo, Sharing), LuData),
+        SharedLU = list.condense(ExtendedLuData),
         HeadVarSharedLU = datastructs_project(HeadVars, SharedLU),
 
         structure_sharing.domain.sharing_as_project(HeadVars, Sharing, 
@@ -558,7 +579,7 @@
             AllDeadHeadVarNodes = [],
             LocalCondition = always
         ;
-            AllDeadHeadVarNodes = [_|_],
+            AllDeadHeadVarNodes = [_ | _],
             % Translate the in use nodes:
             AllInUseNodes = extend_datastructs(ModuleInfo, ProcInfo, 
                 SharingAs, list.append(LuData, CalledInUseNodes)),
@@ -577,17 +598,17 @@
     ). 
 
 reuse_as_satisfied(ModuleInfo, ProcInfo, LiveData, SharingAs, StaticVars,
-        ReuseAs) :- 
+        ReuseAs, Result) :- 
     (
         ReuseAs = no_reuse,
-        fail
+        Result = reuse_not_possible(no_reuse)
     ;
         ReuseAs = unconditional,
-        true
+        Result = reuse_possible
     ; 
         ReuseAs = conditional(Conditions),
-        list.all_true(reuse_condition_satisfied(ModuleInfo, ProcInfo, 
-            LiveData, SharingAs, StaticVars), Conditions),
+        reuse_as_satisfied_2(ModuleInfo, ProcInfo, LiveData, SharingAs,
+            StaticVars, Conditions, Result0),
 
         % Next to verifying each condition separately, one has to verify
         % whether the nodes which are reused in each of the conditions are
@@ -596,8 +617,38 @@
         % the callee want to reuse the different parts of the input while
         % these may point to exactly the same structure, resulting in
         % undefined behaviour.
-        no_aliases_between_reuse_nodes(ModuleInfo, ProcInfo, SharingAs,
-            Conditions)
+        (
+            Result0 = reuse_possible,
+            (
+                no_aliases_between_reuse_nodes(ModuleInfo, ProcInfo,
+                    SharingAs, Conditions)
+            ->
+                Result = reuse_possible
+            ;
+                Result = reuse_not_possible(reuse_nodes_have_sharing)
+            )
+        ;
+            Result0 = reuse_not_possible(_),
+            Result = Result0
+        )
+    ).
+
+:- pred reuse_as_satisfied_2(module_info::in, proc_info::in, livedata::in,
+    sharing_as::in, prog_vars::in, reuse_conditions::in,
+    reuse_satisfied_result::out) is det.
+
+reuse_as_satisfied_2(_, _, _, _, _, [], reuse_possible).
+reuse_as_satisfied_2(ModuleInfo, ProcInfo, LiveData, SharingAs, StaticVars,
+        [Cond | Conds], Result) :- 
+    reuse_condition_satisfied(ModuleInfo, ProcInfo, 
+        LiveData, SharingAs, StaticVars, Cond, Result0),
+    (
+        Result0 = reuse_possible,
+        reuse_as_satisfied_2(ModuleInfo, ProcInfo, LiveData, SharingAs,
+            StaticVars, Conds, Result)
+    ;
+        Result0 = reuse_not_possible(_),
+        Result = Result0
     ).
 
 :- pred no_aliases_between_reuse_nodes(module_info::in, proc_info::in,
@@ -657,31 +708,53 @@
 %-----------------------------------------------------------------------------%
 
 :- pred reuse_condition_satisfied(module_info::in, proc_info::in,
-    livedata::in, sharing_as::in, prog_vars::in, reuse_condition::in) 
-    is semidet.
+    livedata::in, sharing_as::in, prog_vars::in, reuse_condition::in,
+    reuse_satisfied_result::out) is det.
 
 reuse_condition_satisfied(ModuleInfo, ProcInfo, LiveData, SharingAs, 
-        StaticVars, Condition) :- 
+        StaticVars, Condition, Result) :- 
     (
-        Condition = always
+        Condition = always,
+        Result = reuse_possible
     ;
         Condition = condition(DeadNodes, InUseNodes, SharingNodes),
         % Reuse of static vars is not allowed:
         StaticDeadNodes = datastructs_project(StaticVars, DeadNodes),
-        StaticDeadNodes = [],
+        (
+            StaticDeadNodes = [],
 
-        % Using the InUseNodes, and the sharing recorded by the condition, 
-        % compute a new set of livedata that (safely) approximates the
-        % set of livedata that would have been obtained when looking at
-        % the program point from where the reuse condition actually comes from.
-        NewSharing = sharing_as_comb(ModuleInfo, ProcInfo, SharingNodes, 
-            SharingAs),
-        UpdatedLiveData = livedata_add_liveness(ModuleInfo, ProcInfo, 
-            InUseNodes, NewSharing, LiveData),
-        nodes_are_not_live(ModuleInfo, ProcInfo, DeadNodes,
-            UpdatedLiveData)
+            % Using the InUseNodes, and the sharing recorded by the condition, 
+            % compute a new set of livedata that (safely) approximates the
+            % set of livedata that would have been obtained when looking at
+            % the program point from where the reuse condition actually comes
+            % from.
+            NewSharing = sharing_as_comb(ModuleInfo, ProcInfo, SharingNodes, 
+                SharingAs),
+            UpdatedLiveData = livedata_add_liveness(ModuleInfo, ProcInfo, 
+                InUseNodes, NewSharing, LiveData),
+            nodes_are_not_live(ModuleInfo, ProcInfo, DeadNodes,
+                UpdatedLiveData, NotLiveResult),
+            (
+                NotLiveResult = nodes_all_live,
+                Result = reuse_not_possible(unknown_livedata)
+            ;
+                NotLiveResult = nodes_are_live(StillLive),
+                (
+                    StillLive = [],
+                    Result = reuse_possible
+                ;
+                    StillLive = [_ | _],
+                    Vars = datastructs_vars(StillLive),
+                    Result = reuse_not_possible(reuse_condition_violated(Vars))
+                )
+            )
+        ;
+            StaticDeadNodes = [_ | _],
+            Vars = datastructs_vars(StaticDeadNodes),
+            Result = reuse_not_possible(reuse_condition_violated(Vars))
+        )
     ).
-    
+
 %-----------------------------------------------------------------------------%
 
 from_structure_reuse_domain(ReuseDomain) = ReuseAs :- 
Index: compiler/structure_reuse.indirect.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/structure_reuse.indirect.m,v
retrieving revision 1.21
diff -u -r1.21 structure_reuse.indirect.m
--- compiler/structure_reuse.indirect.m	23 Apr 2008 05:16:49 -0000	1.21
+++ compiler/structure_reuse.indirect.m	28 Apr 2008 07:00:21 -0000
@@ -50,11 +50,12 @@
 
 :- import_module analysis.
 :- import_module hlds.hlds_goal.
+:- import_module hlds.hlds_out.
 :- import_module hlds.hlds_pred.
-:- import_module hlds.passes_aux.
 :- import_module libs.compiler_util.
 :- import_module libs.globals.
 :- import_module libs.options.
+:- import_module parse_tree.mercury_to_mercury.
 :- import_module parse_tree.prog_data.
 :- import_module parse_tree.prog_out.
 :- import_module parse_tree.prog_type.
@@ -149,17 +150,28 @@
 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),
 
-    module_info_pred_proc_info(!.ModuleInfo, PPId, PredInfo0, ProcInfo0),
     PPId = proc(PredId, ProcId),
 
     % Some feedback..
-    Run = string.int_to_string(sr_fixpoint_table_which_run(!.FixpointTable)),
-    passes_aux.write_proc_progress_message(
-        "% Indirect reuse analysis (run " ++ Run ++ ") ",
-        PredId, ProcId, !.ModuleInfo, !IO),
+    Run = sr_fixpoint_table_which_run(!.FixpointTable),
+    (
+        ( VeryVerbose = yes
+        ; 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)
+    ;
+        true
+    ),
 
     % 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),
@@ -167,13 +179,23 @@
 
     % The actual analysis of the goal:
     indirect_reuse_analyse_goal(BaseInfo, Goal0, Goal, AnalysisInfo0,
-        AnalysisInfo, !IO),
+        AnalysisInfo),
     !:FixpointTable = AnalysisInfo ^ fptable,
 
     % Some feedback.
-    maybe_write_string(VeryVerbose, "\n% FPT: " ++
-        sr_fixpoint_table_get_short_description(PPId, !.FixpointTable)
-        ++ "\n", !IO),
+    (
+        ( VeryVerbose = yes
+        ; DebugIndirect = yes
+        )
+    ->
+        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,
@@ -198,7 +220,8 @@
                 sharing_table   :: sharing_as_table,
                 reuse_table     :: reuse_as_table,
                 headvars        :: list(prog_var),
-                very_verbose    :: bool
+                very_verbose    :: bool,
+                debug_indirect  :: bool
             ).
 
     % The type analysis_info gathers the analysis information that may change
@@ -227,9 +250,11 @@
 
     module_info_get_globals(ModuleInfo, Globals),
     globals.lookup_bool_option(Globals, very_verbose, VeryVerbose),
+    globals.lookup_bool_option(Globals, debug_indirect_reuse, DebugIndirect),
 
     BG = ir_background_info(ModuleInfo, PredInfo, ProcInfo,
-        SharingTable, ReuseTable, HeadVarsOfInterest, VeryVerbose).
+        SharingTable, ReuseTable, HeadVarsOfInterest, VeryVerbose,
+        DebugIndirect).
 
 :- func analysis_info_init(pred_proc_id, sr_fixpoint_table) = ir_analysis_info.
 
@@ -280,10 +305,9 @@
 %-----------------------------------------------------------------------------%
 
 :- pred indirect_reuse_analyse_goal(ir_background_info::in, hlds_goal::in,
-    hlds_goal::out, ir_analysis_info::in, ir_analysis_info::out,
-    io::di, io::uo) is det.
+    hlds_goal::out, ir_analysis_info::in, ir_analysis_info::out) is det.
 
-indirect_reuse_analyse_goal(BaseInfo, !Goal, !AnalysisInfo, !IO) :-
+indirect_reuse_analyse_goal(BaseInfo, !Goal, !AnalysisInfo) :-
     ModuleInfo = BaseInfo ^ module_info,
     PredInfo = BaseInfo ^ pred_info,
     ProcInfo = BaseInfo ^ proc_info,
@@ -291,15 +315,15 @@
     !.Goal = hlds_goal(GoalExpr0, GoalInfo0),
     (
         GoalExpr0 = conj(ConjType, Goals0),
-        list.map_foldl2(indirect_reuse_analyse_goal_with_progress(BaseInfo),
-            Goals0, Goals, !AnalysisInfo, !IO),
+        list.map_foldl(indirect_reuse_analyse_goal(BaseInfo),
+            Goals0, Goals, !AnalysisInfo),
         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, !IO),
+            CalleeArgs, GoalInfo0, GoalInfo, !AnalysisInfo),
         lookup_sharing_and_comb(ModuleInfo, PredInfo, ProcInfo, SharingTable,
             CalleePredId, CalleeProcId, CalleeArgs,
             !.AnalysisInfo ^ sharing_as, NewSharing),
@@ -344,20 +368,20 @@
             GoalInfo0, !.AnalysisInfo ^ sharing_as)
     ;
         GoalExpr0 = disj(Goals0),
-        list.map2_foldl2(
+        list.map2_foldl(
             indirect_reuse_analyse_disj(BaseInfo, !.AnalysisInfo),
             Goals0, Goals, AnalysisInfoList, !.AnalysisInfo ^ fptable,
-            NewFixpointTable, !IO),
+            NewFixpointTable),
         analysis_info_combine(BaseInfo, AnalysisInfoList, NewFixpointTable,
             !AnalysisInfo),
         GoalExpr = disj(Goals),
         !:Goal = hlds_goal(GoalExpr, GoalInfo0)
     ;
         GoalExpr0 = switch(A, B, Cases0),
-        list.map2_foldl2(
+        list.map2_foldl(
             indirect_reuse_analyse_case(BaseInfo, !.AnalysisInfo),
             Cases0, Cases, AnalysisInfoList, !.AnalysisInfo ^ fptable,
-            NewFixpointTable, !IO),
+            NewFixpointTable),
         analysis_info_combine(BaseInfo, AnalysisInfoList, NewFixpointTable,
             !AnalysisInfo),
         GoalExpr = switch(A, B, Cases),
@@ -368,7 +392,7 @@
     ;
         GoalExpr0 = scope(A, SubGoal0),
         indirect_reuse_analyse_goal(BaseInfo, SubGoal0, SubGoal,
-            !AnalysisInfo, !IO),
+            !AnalysisInfo),
         GoalExpr = scope(A, SubGoal),
         !:Goal = hlds_goal(GoalExpr, GoalInfo0)
     ;
@@ -385,13 +409,13 @@
         GoalExpr0 = if_then_else(A, IfGoal0, ThenGoal0, ElseGoal0),
         AnalysisInfo0 = !.AnalysisInfo,
         indirect_reuse_analyse_goal(BaseInfo, IfGoal0, IfGoal,
-            AnalysisInfo0, AnalysisInfoIfGoal, !IO),
+            AnalysisInfo0, AnalysisInfoIfGoal),
         indirect_reuse_analyse_goal(BaseInfo, ThenGoal0, ThenGoal,
-            AnalysisInfoIfGoal, AnalysisInfoThenGoal, !IO),
+            AnalysisInfoIfGoal, AnalysisInfoThenGoal),
         AnalysisInfoElseGoal0 = AnalysisInfo0 ^ fptable :=
             AnalysisInfoThenGoal ^ fptable,
         indirect_reuse_analyse_goal(BaseInfo, ElseGoal0, ElseGoal,
-            AnalysisInfoElseGoal0, AnalysisInfoElseGoal, !IO),
+            AnalysisInfoElseGoal0, AnalysisInfoElseGoal),
         analysis_info_lub(BaseInfo, AnalysisInfoThenGoal,
             AnalysisInfoElseGoal, !:AnalysisInfo),
         GoalExpr = if_then_else(A, IfGoal, ThenGoal, ElseGoal),
@@ -410,61 +434,53 @@
         unexpected(this_file, "indirect_reuse_analyse_goal: shorthand")
     ).
 
-:- pred indirect_reuse_analyse_goal_with_progress(ir_background_info::in,
-    hlds_goal::in, hlds_goal::out, ir_analysis_info::in, ir_analysis_info::out,
-    io::di, io::uo) is det.
-
-indirect_reuse_analyse_goal_with_progress(BaseInfo, !Goal, !AnalysisInfo,
-        !IO) :-
-    VeryVerbose = BaseInfo ^ very_verbose,
-    (
-        VeryVerbose = yes,
-        io.write_char('.', !IO),
-        io.flush_output(!IO)
-    ;
-        VeryVerbose = no
-    ),
-    indirect_reuse_analyse_goal(BaseInfo, !Goal, !AnalysisInfo, !IO).
-
     % Analyse each branch of a disjunction with respect to an input
     % analysis_info, producing a resulting 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, io::di, io::uo) is det.
+    sr_fixpoint_table::in, sr_fixpoint_table::out) is det.
 
 indirect_reuse_analyse_disj(BaseInfo, AnalysisInfo0, Goal0, Goal, AnalysisInfo,
-        !FixpointTable, !IO) :-
+        !FixpointTable) :-
     % Replace the state of the fixpoint_table in AnalysisInfo0:
     NewAnalysisInfo = AnalysisInfo0 ^ fptable := !.FixpointTable,
     indirect_reuse_analyse_goal(BaseInfo, Goal0, Goal, NewAnalysisInfo,
-        AnalysisInfo, !IO),
+        AnalysisInfo),
     !:FixpointTable = AnalysisInfo ^ 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, io::di, io::uo) is det.
+    sr_fixpoint_table::in, sr_fixpoint_table::out) is det.
 
 indirect_reuse_analyse_case(BaseInfo, AnalysisInfo0, Case0, Case, AnalysisInfo,
-        !FixpointTable, !IO) :-
+        !FixpointTable) :-
     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, !IO),
+        AnalysisInfo),
     !:FixpointTable = AnalysisInfo ^ fptable,
     Case = case(MainConsId, OtherConsIds, Goal).
 
 %-----------------------------------------------------------------------------%
 
+:- type verify_indirect_reuse_reason
+    --->    callee_has_no_reuses
+    ;       callee_has_only_unconditional_reuse
+    ;       current_sharing_is_top
+    ;       reuse_is_unsafe(prog_vars)
+    ;       reuse_is_unconditional
+    ;       reuse_is_conditional.
+
 :- pred verify_indirect_reuse(ir_background_info::in, pred_id::in, proc_id::in,
     prog_vars::in, hlds_goal_info::in, hlds_goal_info::out,
-    ir_analysis_info::in, ir_analysis_info::out, io::di, io::uo) is det.
+    ir_analysis_info::in, ir_analysis_info::out) is det.
 
 verify_indirect_reuse(BaseInfo, CalleePredId, CalleeProcId, CalleeArgs,
-        !GoalInfo, !AnalysisInfo, !IO):-
+        !GoalInfo, !AnalysisInfo) :-
     % Find the reuse information of the called procedure in the reuse table:
     CalleePPId = proc(CalleePredId, CalleeProcId),
     lookup_reuse_as(BaseInfo, CalleePPId, !AnalysisInfo, FormalReuseAs),
@@ -473,16 +489,16 @@
         % If there is no reuse, then nothing can be done.
         reuse_as_no_reuses(FormalReuseAs)
     ->
-        true
+        Reason = callee_has_no_reuses
     ;
         reuse_as_all_unconditional_reuses(FormalReuseAs)
     ->
         % With unconditional reuse, we need to mark that the call is always
-        % a reuse call, yet without implying conditions.
+        % a reuse call.
         reuse_as_add_unconditional(!.AnalysisInfo ^ reuse_as, NewReuseAs),
         !:AnalysisInfo = !.AnalysisInfo ^ reuse_as := NewReuseAs,
-        goal_info_set_reuse(reuse(reuse_call(unconditional_reuse)),
-            !GoalInfo)
+        goal_info_set_reuse(reuse(reuse_call(unconditional_reuse)), !GoalInfo),
+        Reason = callee_has_only_unconditional_reuse
     ;
         % With a conditional reuse, we need to check the conditions. If they
         % are satisfied, these conditions need to be translated to the callers
@@ -497,16 +513,16 @@
             sharing_as_is_top(!.AnalysisInfo ^ sharing_as)
         ->
             % no need to update anything
-            true
+            Reason = current_sharing_is_top
         ;
             verify_indirect_reuse_2(BaseInfo, !.AnalysisInfo, !.GoalInfo,
-                CalleePPId, CalleeArgs, FormalReuseAs,
-                NewAndRenamedReuseAs),
+                CalleePPId, CalleeArgs, FormalReuseAs, NewAndRenamedReuseAs,
+                NotDeadVars),
             (
                 reuse_as_no_reuses(NewAndRenamedReuseAs)
             ->
                 % Don't do anything.
-                true
+                Reason = reuse_is_unsafe(NotDeadVars)
             ;
                 reuse_as_all_unconditional_reuses(NewAndRenamedReuseAs)
             ->
@@ -515,7 +531,8 @@
                     NewReuseAs),
                 !:AnalysisInfo = !.AnalysisInfo ^ reuse_as := NewReuseAs,
                 goal_info_set_reuse(reuse(reuse_call(unconditional_reuse)),
-                    !GoalInfo)
+                    !GoalInfo),
+                Reason = reuse_is_unconditional
             ;
                 % Update reuse information and goal_info:
                 reuse_as_least_upper_bound(BaseInfo ^ module_info,
@@ -524,9 +541,34 @@
                 !:AnalysisInfo = !.AnalysisInfo ^ reuse_as := NewReuseAs,
                 goal_info_set_reuse(
                     potential_reuse(reuse_call(conditional_reuse)),
-                    !GoalInfo)
+                    !GoalInfo),
+                Reason = reuse_is_conditional
             )
         )
+    ),
+
+    % Output the reasoning behind the result.
+    trace [io(!IO)] (
+        DebugIndirect = BaseInfo ^ debug_indirect,
+        (
+            DebugIndirect = yes,
+            ModuleInfo = BaseInfo ^ module_info,
+            GoalReuse = goal_info_get_reuse(!.GoalInfo),
+            Context = goal_info_get_context(!.GoalInfo),
+            proc_info_get_varset(BaseInfo ^ proc_info, VarSet),
+            io.write_string("\tcall to ", !IO),
+            write_pred_proc_id_pair(ModuleInfo, CalleePredId, CalleeProcId,
+                !IO),
+            io.write_string("\n\tfrom ", !IO),
+            write_context(Context, !IO),
+            io.write_string("\n\t\treuse: ", !IO),
+            io.write(GoalReuse, !IO),
+            io.write_string("\n\t\treason: ", !IO),
+            write_verify_indirect_reuse_reason(Reason, VarSet, !IO),
+            io.nl(!IO)
+        ;
+            DebugIndirect = no
+        )
     ).
 
 :- pred lookup_reuse_as(ir_background_info::in, pred_proc_id::in,
@@ -559,10 +601,10 @@
     %
 :- pred verify_indirect_reuse_2(ir_background_info::in, ir_analysis_info::in,
     hlds_goal_info::in, pred_proc_id::in, list(prog_var)::in, reuse_as::in,
-    reuse_as::out) is det.
+    reuse_as::out, prog_vars::out) is det.
 
 verify_indirect_reuse_2(BaseInfo, AnalysisInfo, GoalInfo, CalleePPId,
-        CalleeArgs, FormalReuseAs, NewReuseAs):-
+        CalleeArgs, FormalReuseAs, NewReuseAs, NotDeadVars):-
     ModuleInfo = BaseInfo ^ module_info,
     PredInfo = BaseInfo ^ pred_info,
     ProcInfo = BaseInfo ^ proc_info,
@@ -578,10 +620,11 @@
         SharingAs),
     ProjectedLiveData = livedata_project(CalleeArgs, LiveData),
     StaticVars = set.to_sorted_list(AnalysisInfo ^ static_vars),
+ 
+    reuse_as_satisfied(ModuleInfo, ProcInfo, ProjectedLiveData,
+        SharingAs, StaticVars, ActualReuseAs, Result),
     (
-        reuse_as_satisfied(ModuleInfo, ProcInfo, ProjectedLiveData,
-            SharingAs, StaticVars, ActualReuseAs)
-    ->
+        Result = reuse_possible,
         LFU = goal_info_get_lfu(GoalInfo),
         LBU = goal_info_get_lbu(GoalInfo),
         LU = set.union(LFU, LBU),
@@ -589,9 +632,39 @@
         LuData = list.map(datastruct_init, LuList),
         NewReuseAs = reuse_as_from_called_procedure_to_local_reuse_as(
             ModuleInfo, ProcInfo, BaseInfo ^ headvars, LuData, SharingAs,
-            ActualReuseAs)
+            ActualReuseAs),
+        NotDeadVars = []
+    ;
+        Result = reuse_not_possible(Reason),
+        NewReuseAs = reuse_as_init,  % no reuse
+        (
+            ( Reason = no_reuse
+            ; Reason = unknown_livedata
+            ; Reason = reuse_nodes_have_sharing
+            ),
+            NotDeadVars = []
+        ;
+            Reason = reuse_condition_violated(NotDeadVars)
+        )
+    ).
+
+:- pred write_verify_indirect_reuse_reason(verify_indirect_reuse_reason::in,
+    prog_varset::in, io::di, io::uo) is det.
+
+write_verify_indirect_reuse_reason(Reason, VarSet, !IO) :-
+    (
+        ( Reason = callee_has_no_reuses
+        ; Reason = callee_has_only_unconditional_reuse
+        ; Reason = current_sharing_is_top
+        ; Reason = reuse_is_unconditional
+        ; Reason = reuse_is_conditional
+        ),
+        io.write(Reason, !IO)
     ;
-        NewReuseAs = reuse_as_init  % no reuse
+        Reason = reuse_is_unsafe(Vars),
+        io.write_string("reuse_is_unsafe(", !IO),
+        mercury_output_vars(VarSet, yes, Vars, !IO),
+        io.write_string(")", !IO)
     ).
 
 %-----------------------------------------------------------------------------%
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.560
diff -u -r1.560 user_guide.texi
--- doc/user_guide.texi	18 Mar 2008 03:09:42 -0000	1.560
+++ doc/user_guide.texi	28 Apr 2008 07:00:23 -0000
@@ -6435,6 +6435,12 @@
 @findex --debug-intermodule-analysis
 Output detailed debugging traces of the `--intermodule-analysis' option.
 
+ at sp 1
+ at item --debug-indirect-reuse
+ at findex --debug-indirect-reuse
+Output detailed debugging traces of the indirect reuse pass of
+`--structure-reuse' option.
+
 @end table
 
 @node Output options


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