[m-dev.] inefficiencies when creating the .opt file
Simon TAYLOR
stayl at students.cs.mu.oz.au
Tue Jul 15 18:27:55 AEST 1997
Chris wrote:
> I was just looking at the code for making the .opt files (with
> the intention of adding termination information to the files). I think
> that in some cases the datestamp of the .opt file may be changed
> unnecessarily, causing unnecessary recompilation of other files.
Thanks for spotting that Chris.
Could you please review this diff fixing this and another efficiency problem
with inter-module optimization.
Simon.
Estimated hours taken: 3
Efficiency improvements for inter-module optimization.
compiler/intermod.m
compiler/mercury_compile.m
Fix a bug with the date-stamps and --intermod-unused-args by
delaying calling update_interface and touch_interface_datestamp
until after the unused arguments information has been written to
the .opt.tmp file.
compiler/unused_args.m
Write unused argument information to the .opt.tmp file rather
than the .opt file.
compiler/dead_proc_elim.m
compiler/mercury_compile.m
Add a pass to eliminated dead non-local predicates immediately after
building the HLDS to avoid doing analysis of predicates from .opt
files which are not used.
compiler/hlds_module.m
Add module_info_remove_predicate to remove a predicate completely from
the predicate_table.
Index: dead_proc_elim.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/dead_proc_elim.m,v
retrieving revision 1.29
diff -u -r1.29 dead_proc_elim.m
--- dead_proc_elim.m 1997/06/17 08:19:00 1.29
+++ dead_proc_elim.m 1997/07/15 08:03:54
@@ -4,8 +4,8 @@
% Public License - see the file COPYING in the Mercury distribution.
%-----------------------------------------------------------------------------%
%
-% The job of this module is to delete dead procedures and base_gen_info
-% structures from the HLDS.
+% The job of this module is to delete dead predicates, procedures
+% and base_gen_info structures from the HLDS.
%
% It also computes the usage counts that inlining.m uses for the
% `--inline-single-use' option.
@@ -30,6 +30,14 @@
io__state, io__state).
:- mode dead_proc_elim__eliminate(in, in, out, di, uo) is det.
+ % This is performed immediately after make_hlds.m to avoid doing
+ % semantic checking and optimization on predicates from `.opt'
+ % files which are not used in the current module. This assumes that
+ % the clauses_info is still valid, so it cannot be run after mode
+ % analysis.
+:- pred dead_pred_elim(module_info, module_info).
+:- mode dead_pred_elim(in, out) is det.
+
:- type entity ---> proc(pred_id, proc_id)
; base_gen_info(string, string, int).
@@ -40,7 +48,7 @@
:- implementation.
:- import_module hlds_pred, hlds_goal, hlds_data, prog_data, llds.
-:- import_module passes_aux, globals, options.
+:- import_module passes_aux, globals, options, code_util.
:- import_module int, list, set, queue, map, bool, std_util, require.
%-----------------------------------------------------------------------------%
@@ -574,4 +582,158 @@
BaseGenInfos = [NeuteredBaseGenInfo | BaseGenInfos1]
).
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- type dead_pred_info
+ ---> dead_pred_info(
+ module_info,
+ queue(pred_id), % preds to examine.
+ set(pred_id), % preds examined.
+ set(pred_id), % needed pred_ids.
+ set(sym_name) % pred names needed.
+ ).
+
+dead_pred_elim(ModuleInfo0, ModuleInfo) :-
+ module_info_predids(ModuleInfo0, PredIds),
+ queue__init(Queue0),
+ set__init(Preds0),
+ set__init(Names0),
+ DeadInfo0 = dead_pred_info(ModuleInfo0, Queue0,
+ Preds0, Preds0, Names0),
+ list__foldl(dead_pred_elim_initialize, PredIds,
+ DeadInfo0, DeadInfo1),
+ dead_pred_elim_analyze(DeadInfo1, DeadInfo),
+ DeadInfo = dead_pred_info(ModuleInfo1, _, _, NeededPreds, _),
+ set__list_to_set(PredIds, PredIdSet),
+ set__difference(PredIdSet, NeededPreds, DeadPreds),
+ set__to_sorted_list(DeadPreds, DeadPredList),
+ list__foldl(module_info_remove_predicate, DeadPredList,
+ ModuleInfo1, ModuleInfo).
+
+:- pred dead_pred_elim_initialize(pred_id::in, dead_pred_info::in,
+ dead_pred_info::out) is det.
+
+dead_pred_elim_initialize(PredId, DeadInfo0, DeadInfo) :-
+ DeadInfo0 = dead_pred_info(ModuleInfo, Q0, Ex, Needed, NeededNames0),
+ module_info_pred_info(ModuleInfo, PredId, PredInfo),
+ (
+ pred_info_module(PredInfo, PredModule),
+ (
+ % Don't eliminate special preds since they won't
+ % be actually called from the HLDS until after
+ % polymorphism.
+ code_util__compiler_generated(PredInfo)
+ ;
+ % Don't eliminate preds from mercury_builtin.m since
+ % polymorphism.m needs unify/2 and friends.
+ PredModule = "mercury_builtin"
+ ;
+ % Don't attempt to eliminate local preds here, since we
+ % want to do semantic checking on those even if they
+ % aren't used.
+ \+ pred_info_is_imported(PredInfo),
+ \+ pred_info_import_status(PredInfo, opt_imported)
+ )
+ ->
+ pred_info_name(PredInfo, PredName),
+ set__insert(NeededNames0, qualified(PredModule, PredName),
+ NeededNames),
+ queue__put(Q0, PredId, Q)
+ ;
+ NeededNames = NeededNames0,
+ Q = Q0
+ ),
+ DeadInfo = dead_pred_info(ModuleInfo, Q, Ex, Needed, NeededNames).
+
+:- pred dead_pred_elim_analyze(dead_pred_info::in,
+ dead_pred_info::out) is det.
+
+dead_pred_elim_analyze(DeadInfo0, DeadInfo) :-
+ DeadInfo0 = dead_pred_info(ModuleInfo, Q0, Ex0, Needed0, NeededNames),
+ ( queue__get(Q0, PredId, Q) ->
+ ( set__member(PredId, Ex0) ->
+ DeadInfo2 = dead_pred_info(ModuleInfo, Q,
+ Ex0, Needed0, NeededNames)
+ ;
+ set__insert(Needed0, PredId, Needed),
+ set__insert(Ex0, PredId, Ex),
+ DeadInfo1 = dead_pred_info(ModuleInfo, Q, Ex,
+ Needed, NeededNames),
+ module_info_pred_info(ModuleInfo, PredId, PredInfo),
+ pred_info_clauses_info(PredInfo, ClausesInfo),
+ ClausesInfo = clauses_info(_,_,_,_, Clauses),
+ list__foldl(dead_pred_elim_process_clause, Clauses,
+ DeadInfo1, DeadInfo2)
+ ),
+ dead_pred_elim_analyze(DeadInfo2, DeadInfo)
+ ;
+ DeadInfo = DeadInfo0
+ ).
+
+:- pred dead_pred_elim_process_clause(clause::in, dead_pred_info::in,
+ dead_pred_info::out) is det.
+
+dead_pred_elim_process_clause(clause(_, Goal, _)) -->
+ pre_modecheck_examine_goal(Goal).
+
+:- pred pre_modecheck_examine_goal(hlds_goal::in,
+ dead_pred_info::in, dead_pred_info::out) is det.
+
+pre_modecheck_examine_goal(conj(Goals) - _) -->
+ list__foldl(pre_modecheck_examine_goal, Goals).
+pre_modecheck_examine_goal(disj(Goals, _) - _) -->
+ list__foldl(pre_modecheck_examine_goal, Goals).
+pre_modecheck_examine_goal(if_then_else(_, If, Then, Else, _) - _) -->
+ list__foldl(pre_modecheck_examine_goal, [If, Then, Else]).
+pre_modecheck_examine_goal(switch(_, _, Cases, _) - _) -->
+ { ExamineCase = lambda([Case::in, Info0::in, Info::out] is det, (
+ Case = case(_, Goal),
+ pre_modecheck_examine_goal(Goal, Info0, Info)
+ )) },
+ list__foldl(ExamineCase, Cases).
+pre_modecheck_examine_goal(higher_order_call(_,_,_,_,_) - _) --> [].
+pre_modecheck_examine_goal(not(Goal) - _) -->
+ pre_modecheck_examine_goal(Goal).
+pre_modecheck_examine_goal(some(_, Goal) - _) -->
+ pre_modecheck_examine_goal(Goal).
+pre_modecheck_examine_goal(call(_, _, _, _, _, PredName) - _) -->
+ dead_pred_info_add_pred_name(PredName).
+pre_modecheck_examine_goal(pragma_c_code(_, _, _, _, _, _, _, _) - _) --> [].
+pre_modecheck_examine_goal(unify(_, Rhs, _, _, _) - _) -->
+ pre_modecheck_examine_unify_rhs(Rhs).
+
+:- pred pre_modecheck_examine_unify_rhs(unify_rhs::in,
+ dead_pred_info::in, dead_pred_info::out) is det.
+
+pre_modecheck_examine_unify_rhs(var(_)) --> [].
+pre_modecheck_examine_unify_rhs(functor(Functor, _)) -->
+ ( { Functor = cons(Name, _) } ->
+ dead_pred_info_add_pred_name(Name)
+ ;
+ []
+ ).
+pre_modecheck_examine_unify_rhs(lambda_goal(_, _, _, _, Goal)) -->
+ pre_modecheck_examine_goal(Goal).
+
+:- pred dead_pred_info_add_pred_name(sym_name::in, dead_pred_info::in,
+ dead_pred_info::out) is det.
+
+dead_pred_info_add_pred_name(Name, DeadInfo0, DeadInfo) :-
+ DeadInfo0 = dead_pred_info(ModuleInfo, Q0, Ex, Needed, NeededNames0),
+ ( set__member(Name, NeededNames0) ->
+ DeadInfo = DeadInfo0
+ ;
+ module_info_get_predicate_table(ModuleInfo, PredicateTable),
+ set__insert(NeededNames0, Name, NeededNames),
+ ( predicate_table_search_sym(PredicateTable, Name, PredIds) ->
+ queue__put_list(Q0, PredIds, Q)
+ ;
+ Q = Q0
+ ),
+ DeadInfo = dead_pred_info(ModuleInfo, Q, Ex,
+ Needed, NeededNames)
+ ).
+
+%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
Index: hlds_module.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/hlds_module.m,v
retrieving revision 1.22
diff -u -r1.22 hlds_module.m
--- hlds_module.m 1997/06/29 23:10:40 1.22
+++ hlds_module.m 1997/07/14 07:17:37
@@ -288,6 +288,11 @@
:- pred module_info_remove_predid(module_info, pred_id, module_info).
:- mode module_info_remove_predid(in, in, out) is det.
+ % Completely remove a predicate from a module.
+
+:- pred module_info_remove_predicate(pred_id, module_info, module_info).
+:- mode module_info_remove_predicate(in, in, out) is det.
+
% Once the module_info has been built, we call module_info_optimize
% to attempt to optimize the data structures for lots of accesses
% and relatively few insertion/deletions. (This was useful when
@@ -700,6 +705,13 @@
module_info_set_predicate_table(ModuleInfo0, PredicateTable,
ModuleInfo).
+module_info_remove_predicate(PredId, ModuleInfo0, ModuleInfo) :-
+ module_info_get_predicate_table(ModuleInfo0, PredicateTable0),
+ predicate_table_remove_predicate(PredicateTable0, PredId,
+ PredicateTable),
+ module_info_set_predicate_table(ModuleInfo0, PredicateTable,
+ ModuleInfo).
+
% After we have finished constructing the symbol tables,
% we balance all the binary trees, to improve performance
% in later stages of the compiler.
@@ -825,7 +837,8 @@
% Set the pred_id->pred_info map.
% NB You shouldn't modify the keys in this table, only
- % use predicate_table_insert and predicate_table_remove_predid.
+ % use predicate_table_insert, predicate_table_remove_predid and
+ % predicate_table_remove_predicate.
:- pred predicate_table_set_preds(predicate_table, pred_table, predicate_table).
:- mode predicate_table_set_preds(in, in, out) is det.
@@ -841,6 +854,10 @@
predicate_table).
:- mode predicate_table_remove_predid(in, in, out) is det.
+:- pred predicate_table_remove_predicate(predicate_table, pred_id,
+ predicate_table).
+:- mode predicate_table_remove_predicate(in, in, out) is det.
+
% Search the table for (a) predicates or functions
% (b) predicates only or (c) functions only
% matching this (possibly module-qualified) sym_name.
@@ -1079,6 +1096,81 @@
PredicateTable0 = predicate_table(A, B, PredIds0, D, E, F, G, H, I),
list__delete_all(PredIds0, PredId, PredIds),
PredicateTable = predicate_table(A, B, PredIds, D, E, F, G, H, I).
+
+predicate_table_remove_predicate(PredicateTable0, PredId, PredicateTable) :-
+ PredicateTable0 = predicate_table(Preds0, NextPredId, PredIds0,
+ PredN0, PredNA0, PredMNA0, FuncN0, FuncNA0, FuncMNA0),
+ list__delete_all(PredIds0, PredId, PredIds),
+ map__det_remove(Preds0, PredId, PredInfo, Preds),
+ pred_info_module(PredInfo, Module),
+ pred_info_name(PredInfo, Name),
+ pred_info_arity(PredInfo, Arity),
+ pred_info_get_is_pred_or_func(PredInfo, IsPredOrFunc),
+ (
+ IsPredOrFunc = predicate,
+ predicate_table_remove_from_index(Module, Name, Arity, PredId,
+ PredN0, PredN, PredNA0, PredNA, PredMNA0, PredMNA),
+ PredicateTable = predicate_table(Preds, NextPredId, PredIds,
+ PredN, PredNA, PredMNA, FuncN0, FuncNA0, FuncMNA0)
+ ;
+ IsPredOrFunc = function,
+ FuncArity is Arity - 1,
+ predicate_table_remove_from_index(Module, Name, FuncArity,
+ PredId, FuncN0, FuncN, FuncNA0, FuncNA,
+ FuncMNA0, FuncMNA),
+ PredicateTable = predicate_table(Preds, NextPredId, PredIds,
+ PredN0, PredNA0, PredMNA0, FuncN, FuncNA, FuncMNA)
+ ).
+
+:- pred predicate_table_remove_from_index(string, string, int, pred_id,
+ name_index, name_index, name_arity_index, name_arity_index,
+ module_name_arity_index, module_name_arity_index).
+:- mode predicate_table_remove_from_index(in, in, in, in, in, out,
+ in, out, in, out) is det.
+
+predicate_table_remove_from_index(Module, Name, Arity, PredId,
+ N0, N, NA0, NA, MNA0, MNA) :-
+ do_remove_from_index(N0, Name, PredId, N),
+ do_remove_from_index(NA0, Name / Arity, PredId, NA),
+ do_remove_from_m_n_a_index(MNA0, Module, Name, Arity, PredId, MNA).
+
+:- pred do_remove_from_index(map(T, list(pred_id)), T, pred_id,
+ map(T, list(pred_id))).
+:- mode do_remove_from_index(in, in, in, out) is det.
+
+do_remove_from_index(Index0, T, PredId, Index) :-
+ ( map__search(Index0, T, NamePredIds0) ->
+ list__delete_all(NamePredIds0, PredId, NamePredIds),
+ ( NamePredIds = [] ->
+ map__delete(Index0, T, Index)
+ ;
+ map__det_update(Index0, T, NamePredIds, Index)
+ )
+ ;
+ Index = Index0
+ ).
+
+:- pred do_remove_from_m_n_a_index(module_name_arity_index,
+ string, string, int, pred_id, module_name_arity_index).
+:- mode do_remove_from_m_n_a_index(in, in, in, in, in, out) is det.
+
+do_remove_from_m_n_a_index(MNA0, Module, Name, Arity, PredId, MNA) :-
+ map__lookup(MNA0, Module - Name, Arities0),
+ map__lookup(Arities0, Arity, PredIds0),
+ list__delete_all(PredIds0, PredId, PredIds),
+ ( PredIds = [] ->
+ map__delete(Arities0, Arity, Arities),
+ ( map__is_empty(Arities) ->
+ map__delete(MNA0, Module - Name, MNA)
+ ;
+ map__det_update(MNA0, Module - Name, Arities, MNA)
+ )
+ ;
+ map__det_update(Arities0, Arity, PredIds, Arities),
+ map__det_update(MNA0, Module - Name, Arities, MNA)
+ ).
+
+%-----------------------------------------------------------------------------%
:- pred predicate_table_reverse_predids(predicate_table, predicate_table).
:- mode predicate_table_reverse_predids(in, out) is det.
Index: intermod.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/intermod.m,v
retrieving revision 1.27
diff -u -r1.27 intermod.m
--- intermod.m 1997/06/29 23:10:49 1.27
+++ intermod.m 1997/07/14 07:44:20
@@ -109,8 +109,6 @@
PredDecls, IntermodInfo4, IntermodInfo) },
intermod__write_intermod_info(IntermodInfo),
io__told,
- { string__append(ModuleName, ".opt", OptName) },
- update_interface(OptName),
globals__io_lookup_bool_option(intermod_unused_args,
UnusedArgs),
( { UnusedArgs = yes } ->
@@ -118,8 +116,7 @@
ModuleInfo1, ModuleInfo) }
;
{ ModuleInfo = ModuleInfo1 }
- ),
- touch_interface_datestamp(ModuleName, ".optdate")
+ )
).
% a collection of stuff to go in the .opt file
Index: mercury_compile.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/mercury_compile.m,v
retrieving revision 1.46
diff -u -r1.46 mercury_compile.m
--- mercury_compile.m 1997/07/08 05:54:43 1.46
+++ mercury_compile.m 1997/07/14 09:53:06
@@ -284,7 +284,16 @@
( { FoundError = yes ; IntermodError = yes } ->
{ module_info_incr_errors(HLDS0, HLDS1) }
;
- { HLDS1 = HLDS0 }
+ globals__io_lookup_bool_option(intermodule_optimization,
+ Intermod),
+ globals__io_lookup_bool_option(make_optimization_interface,
+ MakeOptInt),
+ ( { Intermod = yes, MakeOptInt = no } ->
+ % Eliminate unnecessary clauses from `.opt' files.
+ { dead_pred_elim(HLDS0, HLDS1) }
+ ;
+ { HLDS1 = HLDS0 }
+ )
).
:- pred mercury_compile__module_qualify_items(item_list, item_list, string,
@@ -449,8 +458,8 @@
% If intermod_unused_args is being performed, run mode and
% determinism analysis and polymorphism, then run unused_args
- % to append the unused argument information to the `.opt' file
- % written above.
+ % to append the unused argument information to the `.opt.tmp'
+ % file written above.
( { IntermodArgs = yes } ->
mercury_compile__frontend_pass_2_by_phases(
HLDS1, HLDS2, FoundModeError),
@@ -465,7 +474,11 @@
)
;
{ HLDS = HLDS1 }
- )
+ ),
+ { module_info_name(HLDS, ModuleName) },
+ { string__append(ModuleName, ".opt", OptName) },
+ update_interface(OptName),
+ touch_interface_datestamp(ModuleName, ".optdate")
;
{ HLDS = HLDS0 }
).
Index: unused_args.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/unused_args.m,v
retrieving revision 1.31
diff -u -r1.31 unused_args.m
--- unused_args.m 1997/06/29 23:11:38 1.31
+++ unused_args.m 1997/07/14 07:36:28
@@ -93,7 +93,7 @@
globals__io_lookup_bool_option(make_optimization_interface, MakeOpt),
( { MakeOpt = yes } ->
{ module_info_name(ModuleInfo0, ModuleName) },
- { string__append(ModuleName, ".opt", OptFileName) },
+ { string__append(ModuleName, ".opt.tmp", OptFileName) },
io__open_append(OptFileName, OptFileRes),
( { OptFileRes = ok(OptFile) } ->
{ MaybeOptFile = yes(OptFile) }
More information about the developers
mailing list