mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-17 06:47:17 +00:00
Estimated hours taken: 12 Branches: main Switch from using set(prog_var), which is represented using set_ordlist, to set_of_progvar, which is represented using tree_bitset, for most sets of variables in the compiler, including the nonlocals sets in goal_infos. This diff yields about a 5% speedup when compiling the training_cars_full.m stress test, but also about a 1% slowdown on tools/speedtest. Both of these are with the current default state in which tree_bitset is compiled with a whole bunch of sanity checks. If these are disabled, we get roughly a 1% speedup on tools/speedtest. I intend to disable those sanity checks after a shakedown period of a week or two in which the updated version of the compiler is installed on our platforms. compiler/hlds_goal.m: Replace almost all occurrences of set(prog_var) with set_of_progvar. The main exceptions are the types supporting rbmm. compiler/set_of_var.m: Add some more predicates and functions that previous existed on sets but not yet on set_of_vars. compiler/*.m: Conform to the change in hlds_goal.m, and make similar changes in set representations. library/bag.m: Add a predicate and function for creating a bag from a sorted list. We already had them for creating a bag from a set, but a set_of_progvar shouldn't have to be converted to a set. library/robdd.m: Fix deviations from our programming style.
283 lines
12 KiB
Mathematica
283 lines
12 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1996-2000,2002-2011 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% File: det_util.m.
|
|
% Main authors: fjh, zs.
|
|
%
|
|
% Utility predicates used in two or more of the modules concerned with
|
|
% determinism: switch_detection, cse_detection, det_analysis, det_report
|
|
% and simplify.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module check_hlds.det_util.
|
|
:- interface.
|
|
|
|
:- import_module hlds.
|
|
:- import_module hlds.hlds_data.
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module hlds.instmap.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.error_util.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.set_of_var.
|
|
|
|
:- import_module bool.
|
|
:- import_module list.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type maybe_changed
|
|
---> changed
|
|
; unchanged.
|
|
|
|
% Should we emit an error message about extra variables in the head
|
|
% of a promise_equivalent_solutions scope? Extra variables are
|
|
% those non-locals that are not further bound or (potentially) constrained
|
|
% by the goal inside the scope.
|
|
%
|
|
% We ignore such extra variables when re-running determinism
|
|
% analysis after optimisations such as inlining have been performed
|
|
% because not doing so results in spurious error messages.
|
|
% (Inlining can cause variables that had inst any to become ground.)
|
|
%
|
|
:- type report_pess_extra_vars
|
|
---> pess_extra_vars_report
|
|
% Emit an error message if the head of a
|
|
% promise_equivalent_solutions scope contains variables that
|
|
% are not further bound or (potentially) further constrained
|
|
% by the goal inside the scope.
|
|
|
|
; pess_extra_vars_ignore.
|
|
% Do not emit an error message if the above occurs.
|
|
|
|
% Does the predicate being analyzed contain a require_complete_switch
|
|
% or require_detism scope?
|
|
%
|
|
:- type contains_require_scope
|
|
---> does_not_contain_require_scope
|
|
; contains_require_scope.
|
|
|
|
% Does the predicate being analyzed contain a call that can be optimized
|
|
% by format_call.m?
|
|
%
|
|
:- type contains_format_call
|
|
---> does_not_contain_format_call
|
|
; contains_format_call.
|
|
|
|
:- type det_info.
|
|
|
|
% Given a list of cases, and a list of the possible cons_ids
|
|
% that the switch variable could be bound to, select out only
|
|
% those cases whose cons_id occurs in the list of possible cons_ids.
|
|
%
|
|
:- pred delete_unreachable_cases(list(case)::in, list(cons_id)::in,
|
|
list(case)::out) is det.
|
|
|
|
% Update the current substitution to account for the effects
|
|
% of the given unification.
|
|
%
|
|
:- pred interpret_unify(prog_var::in, unify_rhs::in,
|
|
prog_substitution::in, prog_substitution::out) is semidet.
|
|
|
|
% Look up the determinism of a procedure, and also return the pred_info
|
|
% containing the procedure. Doing both at once allows a small speedup.
|
|
%
|
|
:- pred det_lookup_pred_info_and_detism(det_info::in, pred_id::in, proc_id::in,
|
|
pred_info::out, determinism::out) is det.
|
|
|
|
:- pred det_get_proc_info(det_info::in, proc_info::out) is det.
|
|
|
|
:- pred det_lookup_var_type(module_info::in, proc_info::in, prog_var::in,
|
|
hlds_type_defn::out) is semidet.
|
|
|
|
:- pred det_no_output_vars(set_of_progvar::in, instmap::in, instmap_delta::in,
|
|
det_info::in) is semidet.
|
|
|
|
:- pred det_info_add_error_spec(error_spec::in, det_info::in, det_info::out)
|
|
is det.
|
|
|
|
:- pred det_info_init(module_info::in, vartypes::in, pred_id::in, proc_id::in,
|
|
report_pess_extra_vars::in, list(error_spec)::in, det_info::out) is det.
|
|
|
|
:- pred det_info_get_module_info(det_info::in, module_info::out) is det.
|
|
:- pred det_info_get_pred_id(det_info::in, pred_id::out) is det.
|
|
:- pred det_info_get_proc_id(det_info::in, proc_id::out) is det.
|
|
:- pred det_info_get_reorder_conj(det_info::in, bool::out) is det.
|
|
:- pred det_info_get_reorder_disj(det_info::in, bool::out) is det.
|
|
:- pred det_info_get_fully_strict(det_info::in, bool::out) is det.
|
|
:- pred det_info_get_vartypes(det_info::in, vartypes::out) is det.
|
|
:- pred det_info_get_pess_extra_vars(det_info::in,
|
|
report_pess_extra_vars::out) is det.
|
|
:- pred det_info_get_has_format_call(det_info::in,
|
|
contains_format_call::out) is det.
|
|
:- pred det_info_get_has_req_scope(det_info::in,
|
|
contains_require_scope::out) is det.
|
|
:- pred det_info_get_error_specs(det_info::in, list(error_spec)::out) is det.
|
|
|
|
:- pred det_info_set_module_info(module_info::in, det_info::in, det_info::out)
|
|
is det.
|
|
:- pred det_info_set_vartypes(vartypes::in, det_info::in, det_info::out)
|
|
is det.
|
|
:- pred det_info_set_has_format_call(det_info::in, det_info::out) is det.
|
|
:- pred det_info_set_has_req_scope(det_info::in, det_info::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module libs.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.options.
|
|
:- import_module parse_tree.prog_type.
|
|
:- import_module parse_tree.prog_util.
|
|
|
|
:- import_module map.
|
|
:- import_module set_tree234.
|
|
:- import_module term.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
delete_unreachable_cases(Cases0, PossibleConsIds, Cases) :-
|
|
PossibleConsIdSet = set_tree234.list_to_set(PossibleConsIds),
|
|
% We use a reverse list accumulator because we want to avoid requiring
|
|
% O(n) stack space.
|
|
delete_unreachable_cases_2(Cases0, PossibleConsIdSet, [], RevCases),
|
|
list.reverse(RevCases, Cases).
|
|
|
|
:- pred delete_unreachable_cases_2(list(case)::in, set_tree234(cons_id)::in,
|
|
list(case)::in, list(case)::out) is det.
|
|
|
|
delete_unreachable_cases_2([], _PossibleConsIdSet, !RevCases).
|
|
delete_unreachable_cases_2([Case0 | Cases0], PossibleConsIdSet, !RevCases) :-
|
|
Case0 = case(MainConsId0, OtherConsIds0, Goal),
|
|
( set_tree234.contains(PossibleConsIdSet, MainConsId0) ->
|
|
list.filter(set_tree234.contains(PossibleConsIdSet),
|
|
OtherConsIds0, OtherConsIds),
|
|
Case = case(MainConsId0, OtherConsIds, Goal),
|
|
!:RevCases = [Case | !.RevCases]
|
|
;
|
|
list.filter(set_tree234.contains(PossibleConsIdSet),
|
|
OtherConsIds0, OtherConsIds1),
|
|
(
|
|
OtherConsIds1 = []
|
|
% We don't add Case to !RevCases, effectively deleting it.
|
|
;
|
|
OtherConsIds1 = [MainConsId | OtherConsIds],
|
|
Case = case(MainConsId, OtherConsIds, Goal),
|
|
!:RevCases = [Case | !.RevCases]
|
|
)
|
|
),
|
|
delete_unreachable_cases_2(Cases0, PossibleConsIdSet, !RevCases).
|
|
|
|
interpret_unify(X, rhs_var(Y), !Subst) :-
|
|
unify_term(variable(X, context_init), variable(Y, context_init), !Subst).
|
|
interpret_unify(X, rhs_functor(ConsId, _, ArgVars), !Subst) :-
|
|
term.var_list_to_term_list(ArgVars, ArgTerms),
|
|
cons_id_and_args_to_term(ConsId, ArgTerms, RhsTerm),
|
|
unify_term(variable(X, context_init), RhsTerm, !Subst).
|
|
interpret_unify(_X, rhs_lambda_goal(_, _, _, _, _, _, _, _, _), !Subst).
|
|
% For ease of implementation we just ignore unifications with lambda terms.
|
|
% This is a safe approximation, it just prevents us from optimizing them
|
|
% as well as we would like.
|
|
|
|
det_lookup_pred_info_and_detism(DetInfo, PredId, ModeId, PredInfo, Detism) :-
|
|
det_info_get_module_info(DetInfo, ModuleInfo),
|
|
module_info_get_preds(ModuleInfo, PredTable),
|
|
map.lookup(PredTable, PredId, PredInfo),
|
|
pred_info_get_procedures(PredInfo, ProcTable),
|
|
map.lookup(ProcTable, ModeId, ProcInfo),
|
|
proc_info_interface_determinism(ProcInfo, Detism).
|
|
|
|
det_get_proc_info(DetInfo, ProcInfo) :-
|
|
det_info_get_module_info(DetInfo, ModuleInfo),
|
|
det_info_get_pred_id(DetInfo, PredId),
|
|
det_info_get_proc_id(DetInfo, ProcId),
|
|
module_info_get_preds(ModuleInfo, PredTable),
|
|
map.lookup(PredTable, PredId, PredInfo),
|
|
pred_info_get_procedures(PredInfo, ProcTable),
|
|
map.lookup(ProcTable, ProcId, ProcInfo).
|
|
|
|
det_lookup_var_type(ModuleInfo, ProcInfo, Var, TypeDefn) :-
|
|
proc_info_get_vartypes(ProcInfo, VarTypes),
|
|
map.lookup(VarTypes, Var, Type),
|
|
type_to_ctor_det(Type, TypeCtor),
|
|
module_info_get_type_table(ModuleInfo, TypeTable),
|
|
search_type_ctor_defn(TypeTable, TypeCtor, TypeDefn).
|
|
|
|
det_no_output_vars(Vars, InstMap, InstMapDelta, DetInfo) :-
|
|
det_info_get_module_info(DetInfo, ModuleInfo),
|
|
instmap_delta_no_output_vars(InstMap, InstMapDelta, Vars,
|
|
DetInfo ^ di_vartypes, ModuleInfo).
|
|
|
|
det_info_add_error_spec(Spec, !DetInfo) :-
|
|
det_info_get_error_specs(!.DetInfo, Specs0),
|
|
Specs = [Spec | Specs0],
|
|
det_info_set_error_specs(Specs, !DetInfo).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type det_info
|
|
---> det_info(
|
|
di_module_info :: module_info,
|
|
di_vartypes :: vartypes,
|
|
di_pred_id :: pred_id, % the id of the proc
|
|
di_proc_id :: proc_id, % currently processed
|
|
di_reorder_conj :: bool, % --reorder-conj
|
|
di_reorder_disj :: bool, % --reorder-disj
|
|
di_fully_strict :: bool, % --fully-strict
|
|
di_pess_extra_vars :: report_pess_extra_vars,
|
|
di_has_format_call :: contains_format_call,
|
|
di_has_req_scope :: contains_require_scope,
|
|
di_error_specs :: list(error_spec)
|
|
).
|
|
|
|
det_info_init(ModuleInfo, VarTypes, PredId, ProcId, PessExtraVars,
|
|
Specs, DetInfo) :-
|
|
module_info_get_globals(ModuleInfo, Globals),
|
|
globals.lookup_bool_option(Globals, reorder_conj, ReorderConj),
|
|
globals.lookup_bool_option(Globals, reorder_disj, ReorderDisj),
|
|
globals.lookup_bool_option(Globals, fully_strict, FullyStrict),
|
|
DetInfo = det_info(ModuleInfo, VarTypes, PredId, ProcId,
|
|
ReorderConj, ReorderDisj, FullyStrict, PessExtraVars,
|
|
does_not_contain_format_call, does_not_contain_require_scope,
|
|
Specs).
|
|
|
|
det_info_get_module_info(DI, DI ^ di_module_info).
|
|
det_info_get_pred_id(DI, DI ^ di_pred_id).
|
|
det_info_get_proc_id(DI, DI ^ di_proc_id).
|
|
det_info_get_reorder_conj(DI, DI ^ di_reorder_conj).
|
|
det_info_get_reorder_disj(DI, DI ^ di_reorder_disj).
|
|
det_info_get_fully_strict(DI, DI ^ di_fully_strict).
|
|
det_info_get_vartypes(DI, DI ^ di_vartypes).
|
|
det_info_get_pess_extra_vars(DI, DI ^ di_pess_extra_vars).
|
|
det_info_get_has_format_call(DI, DI ^ di_has_format_call).
|
|
det_info_get_has_req_scope(DI, DI ^ di_has_req_scope).
|
|
det_info_get_error_specs(DI, DI ^ di_error_specs).
|
|
|
|
:- pred det_info_set_error_specs(list(error_spec)::in,
|
|
det_info::in, det_info::out) is det.
|
|
|
|
det_info_set_module_info(ModuleInfo, !DetInfo) :-
|
|
!DetInfo ^ di_module_info := ModuleInfo.
|
|
det_info_set_vartypes(VarTypes, !DetInfo) :-
|
|
!DetInfo ^ di_vartypes := VarTypes.
|
|
det_info_set_has_format_call(!DetInfo) :-
|
|
!DetInfo ^ di_has_format_call := contains_format_call.
|
|
det_info_set_has_req_scope(!DetInfo) :-
|
|
!DetInfo ^ di_has_req_scope := contains_require_scope.
|
|
det_info_set_error_specs(Specs, !DetInfo) :-
|
|
!DetInfo ^ di_error_specs := Specs.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- end_module det_util.
|
|
%-----------------------------------------------------------------------------%
|