[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