[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