mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-17 02:13:54 +00:00
In the process, restrict the use of these types to just those modules
that need to provide services both other modules that use var_tables,
and modules that do not. The latter are modules that either can,
or always do, execute before var_tables are set up.
In some cases, code that previously operated on e.g. var_name_sources
had all its callers converted to use var_tables. In those cases, replace
the use of var_name_sources with var_tables directly.
In other cases, code that previously operated on e.g. var_name_sources
still has some callers that use varsets. In those cases,
- provide versions using var_tables if most callers use var_tables,
renaming predicates/functions to make this the version seem the default,
- leave the operation to work on var_name_sources if some its callers
also have only var_name_sources,
- if there are no such callers, keep just the two versions operating
on varsets and var_tables respectively.
compiler/var_db.m:
compiler/var_table.m:
Move the part of var_table.m that contains the definitions
of the above three types, and the operations on them, to the
new module var_db.m. Only 25 modules currently need var_db.m,
compared to 176 for var_table.m.
compiler/parse_tree.m:
compiler/notes/compiler_design.html:
Add and document the new module.
compiler/parse_tree_out_term.m:
Add a "_vs" suffix to the names of operations that print variables
or terms using varsets, and reuse their old names for versions
that use var_table arguments. For the operations that need var_name_source
versions, make it just select between the varset and var_table versions.
compiler/hlds_out_goal.m:
compiler/instmap.m:
compiler/hlds_out_mode.m:
compiler/hlds_out_util.m:
compiler/hlds_pred.m:
compiler/pd_info.m:
Change some predicates that used to operate on var_{name,type}_sources
to operate on var_tables.
In hlds_out_mode.m, delete some unused predicates, and stop exporting
a predicate whose only caller is local.
compiler/*.m:
Conform to the changes above.
388 lines
15 KiB
Mathematica
388 lines
15 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 2018 The Mercury team.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% This module is intended to help implement the transition
|
|
% from the original mode analysis algorithm implemented by modes.m
|
|
% and related modules to the new propagation based constraint solver.
|
|
% It is intended to represent an interface between mode analysis
|
|
% on the one hand, and the rest of the compiler on the other hand,
|
|
% that is sufficiently abstract that it could be implemented on top of
|
|
% both mode analysis systems. Initially, it will be implemented
|
|
% on top of the old mode analysis system. Once the rest of the compiler
|
|
% is transitioned to use this interface, we will transition its
|
|
% implementation to the propagation based constraint solver.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module hlds.goal_mode.
|
|
:- interface.
|
|
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.prog_rename.
|
|
:- import_module parse_tree.var_table.
|
|
|
|
:- import_module list.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% The goal_mode type, and its initialization.
|
|
%
|
|
|
|
% The representation of the bindings that a goal makes to the variables
|
|
% of a goal.
|
|
%
|
|
:- type goal_mode.
|
|
|
|
% Create a dummy goal_mode to put into goals before mode analysis is run.
|
|
%
|
|
:- func make_dummy_goal_mode = goal_mode.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Tests on goal modes.
|
|
%
|
|
% A pass can call these modes if it has ensured that the goal_modes
|
|
% in goal_infos are up to date. It can do that by invoking
|
|
% compute_goal_modes_in_module when it starts.
|
|
%
|
|
|
|
% There are no tests on goal_modes as yet.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Misc utility operations on goal modes.
|
|
%
|
|
|
|
% rename_vars_in_goal_mode(Must, Subn, !GoalMode):
|
|
%
|
|
% Apply the given substitution to !GoalMode.
|
|
%
|
|
:- pred rename_vars_in_goal_mode(must_rename::in, prog_var_renaming::in,
|
|
goal_mode::in, goal_mode::out) is det.
|
|
|
|
% dump_goal_mode(Prefix, VarTable, GoalMode) = Strs:
|
|
%
|
|
% Return a representation of the given GoalMode that is suitable
|
|
% for use in a HLDS dump. Each Str in Strs should be the contents
|
|
% of a line, including the final newline. Every line should start
|
|
% with Prefix.
|
|
%
|
|
:- func dump_goal_mode(string, var_table, goal_mode) = list(string).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Filling in the goal mode fields.
|
|
%
|
|
|
|
% Fill in the goal_mode fields of every goal in every valid procedure
|
|
% in every valid predicate in the module.
|
|
%
|
|
% At the moment, this filling in is done using the information contained
|
|
% in the goals' instmap_deltas, so this predicate may be called
|
|
% only after the original mode checker has been run.
|
|
%
|
|
:- pred compute_goal_modes_in_module(module_info::in, module_info::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module check_hlds.
|
|
:- import_module check_hlds.inst_match.
|
|
:- import_module check_hlds.inst_test.
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module hlds.instmap.
|
|
:- import_module parse_tree.parse_tree_out_term.
|
|
:- import_module parse_tree.set_of_var.
|
|
|
|
:- import_module map.
|
|
:- import_module require.
|
|
:- import_module set_tree234.
|
|
:- import_module string.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type goal_mode
|
|
---> gm_unreachable
|
|
; gm_reachable(
|
|
% The set of variables bound (i.e. further instantiated)
|
|
% by the goal.
|
|
%
|
|
% The values of the _grounded and _not_grounded fields
|
|
% will always partition the value of this field.
|
|
gm_more_bound :: set_of_progvar,
|
|
|
|
% The subset of gm_more_bound whose final instantiation state
|
|
% is an inst representing a ground term (an inst describing
|
|
% a term containing no variables; *not* just the inst `ground'
|
|
% itself).
|
|
gm_more_bound_grounded :: set_of_progvar,
|
|
|
|
% The subset of gm_more_bound whose final instantiation state
|
|
% is an inst that describes terms that *do* contain variables.
|
|
gm_more_bound_not_grounded :: set_of_progvar
|
|
).
|
|
|
|
make_dummy_goal_mode = gm_unreachable.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rename_vars_in_goal_mode(Must, Subn, !GoalMode) :-
|
|
(
|
|
!.GoalMode = gm_unreachable
|
|
;
|
|
!.GoalMode = gm_reachable(Bound0, BoundGrounded0, BoundNonGrounded0),
|
|
rename_vars_in_set_of_var(Must, Subn, Bound0, Bound),
|
|
rename_vars_in_set_of_var(Must, Subn, BoundGrounded0, BoundGrounded),
|
|
rename_vars_in_set_of_var(Must, Subn, BoundNonGrounded0,
|
|
BoundNonGrounded),
|
|
!:GoalMode = gm_reachable(Bound, BoundGrounded, BoundNonGrounded)
|
|
).
|
|
|
|
dump_goal_mode(PrefixStr, VarTable, GoalMode) = !:DumpStrs :-
|
|
(
|
|
GoalMode = gm_unreachable,
|
|
!:DumpStrs = [PrefixStr ++ "gm_unreachable\n"]
|
|
;
|
|
GoalMode = gm_reachable(_Bound, BoundGrounded, BoundNonGrounded),
|
|
% We don't need to dump _Bound, because _Bound is the union of
|
|
% BoundGrounded and BoundNonGrounded.
|
|
BoundGroundedVars = set_of_var.to_sorted_list(BoundGrounded),
|
|
BoundNonGroundedVars = set_of_var.to_sorted_list(BoundNonGrounded),
|
|
( if BoundGroundedVars = [], BoundNonGroundedVars = [] then
|
|
!:DumpStrs = [PrefixStr ++ "gm_reachable, no vars bound\n"]
|
|
else
|
|
% The gm_reachable part is implicit in the presence of
|
|
% one or both of the following lines.
|
|
(
|
|
BoundNonGroundedVars = [],
|
|
!:DumpStrs = []
|
|
;
|
|
BoundNonGroundedVars = [_ | _],
|
|
NGVarsStr = mercury_vars_to_string(VarTable,
|
|
print_name_and_num, BoundNonGroundedVars),
|
|
string.format("%sbound but not grounded:%s\n",
|
|
[s(PrefixStr), s(NGVarsStr)], NonGroundedStr),
|
|
!:DumpStrs = [NonGroundedStr]
|
|
),
|
|
(
|
|
BoundGroundedVars = []
|
|
;
|
|
BoundGroundedVars = [_ | _],
|
|
GVarsStr = mercury_vars_to_string(VarTable,
|
|
print_name_and_num, BoundNonGroundedVars),
|
|
string.format("%sbound and grounded:%s\n",
|
|
[s(PrefixStr), s(GVarsStr)], GroundedStr),
|
|
!:DumpStrs = [GroundedStr | !.DumpStrs]
|
|
)
|
|
)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
compute_goal_modes_in_module(!ModuleInfo) :-
|
|
module_info_get_valid_pred_id_set(!.ModuleInfo, ValidPredIds),
|
|
module_info_get_pred_id_table(!.ModuleInfo, PredIdTable0),
|
|
map.map_values(compute_goal_modes_in_pred(!.ModuleInfo, ValidPredIds),
|
|
PredIdTable0, PredIdTable),
|
|
module_info_set_pred_id_table(PredIdTable, !ModuleInfo).
|
|
|
|
:- pred compute_goal_modes_in_pred(module_info::in, set_tree234(pred_id)::in,
|
|
pred_id::in, pred_info::in, pred_info::out) is det.
|
|
|
|
compute_goal_modes_in_pred(ModuleInfo, ValidPredIds, PredId, !PredInfo) :-
|
|
( if set_tree234.member(PredId, ValidPredIds) then
|
|
pred_info_get_proc_table(!.PredInfo, ProcTable0),
|
|
map.map_values_only(compute_goal_modes_in_proc(ModuleInfo),
|
|
ProcTable0, ProcTable),
|
|
pred_info_set_proc_table(ProcTable, !PredInfo)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred compute_goal_modes_in_proc(module_info::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
|
|
compute_goal_modes_in_proc(ModuleInfo, !ProcInfo) :-
|
|
( if proc_info_is_valid_mode(!.ProcInfo) then
|
|
proc_info_get_var_table(!.ProcInfo, VarTable),
|
|
proc_info_get_initial_instmap(ModuleInfo, !.ProcInfo, InstMap0),
|
|
proc_info_get_goal(!.ProcInfo, Goal0),
|
|
compute_goal_modes_in_goal(ModuleInfo, VarTable, InstMap0, _InstMap,
|
|
Goal0, Goal),
|
|
proc_info_set_goal(Goal, !ProcInfo)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred compute_goal_modes_in_goal(module_info::in, var_table::in,
|
|
instmap::in, instmap::out, hlds_goal::in, hlds_goal::out) is det.
|
|
|
|
compute_goal_modes_in_goal(ModuleInfo, VarTable, InstMap0, InstMap,
|
|
Goal0, Goal) :-
|
|
Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
|
|
InstMapDelta = goal_info_get_instmap_delta(GoalInfo0),
|
|
(
|
|
( GoalExpr0 = unify(_, _, _, _, _)
|
|
; GoalExpr0 = plain_call(_, _, _, _, _, _)
|
|
; GoalExpr0 = generic_call(_, _, _, _, _)
|
|
; GoalExpr0 = call_foreign_proc(_, _, _, _, _, _, _)
|
|
),
|
|
GoalExpr = GoalExpr0
|
|
;
|
|
GoalExpr0 = conj(ConjType, Conjuncts0),
|
|
compute_goal_modes_in_conj(ModuleInfo, VarTable, InstMap0,
|
|
Conjuncts0, Conjuncts),
|
|
GoalExpr = conj(ConjType, Conjuncts)
|
|
;
|
|
GoalExpr0 = disj(Disjuncts0),
|
|
compute_goal_modes_in_disj(ModuleInfo, VarTable, InstMap0,
|
|
Disjuncts0, Disjuncts),
|
|
GoalExpr = disj(Disjuncts)
|
|
;
|
|
GoalExpr0 = switch(Var, CanFail, Cases0),
|
|
compute_goal_modes_in_switch(ModuleInfo, VarTable, InstMap0,
|
|
Cases0, Cases),
|
|
GoalExpr = switch(Var, CanFail, Cases)
|
|
;
|
|
GoalExpr0 = if_then_else(Vars, CondGoal0, ThenGoal0, ElseGoal0),
|
|
compute_goal_modes_in_goal(ModuleInfo, VarTable, InstMap0, InstMapCond,
|
|
CondGoal0, CondGoal),
|
|
compute_goal_modes_in_goal(ModuleInfo, VarTable, InstMapCond, _,
|
|
ThenGoal0, ThenGoal),
|
|
compute_goal_modes_in_goal(ModuleInfo, VarTable, InstMap0, _,
|
|
ElseGoal0, ElseGoal),
|
|
GoalExpr = if_then_else(Vars, CondGoal, ThenGoal, ElseGoal)
|
|
;
|
|
GoalExpr0 = negation(SubGoal0),
|
|
compute_goal_modes_in_goal(ModuleInfo, VarTable, InstMap0, _,
|
|
SubGoal0, SubGoal),
|
|
GoalExpr = negation(SubGoal)
|
|
;
|
|
GoalExpr0 = scope(Reason, SubGoal0),
|
|
compute_goal_modes_in_goal(ModuleInfo, VarTable, InstMap0, _,
|
|
SubGoal0, SubGoal),
|
|
GoalExpr = scope(Reason, SubGoal)
|
|
;
|
|
GoalExpr0 = shorthand(Shorthand0),
|
|
(
|
|
Shorthand0 = bi_implication(_, _),
|
|
unexpected($pred, "bi_implication")
|
|
;
|
|
Shorthand0 = try_goal(MaybeIOVars, ResultVar, SubGoal0),
|
|
compute_goal_modes_in_goal(ModuleInfo, VarTable, InstMap0, _,
|
|
SubGoal0, SubGoal),
|
|
Shorthand = try_goal(MaybeIOVars, ResultVar, SubGoal)
|
|
;
|
|
Shorthand0 = atomic_goal(AtomicGoalType, OuterVars, InnerVars,
|
|
OutputVars, MainGoal0, OrElseGoals0, OrElseInners),
|
|
compute_goal_modes_in_goal(ModuleInfo, VarTable, InstMap0, _,
|
|
MainGoal0, MainGoal),
|
|
compute_goal_modes_in_disj(ModuleInfo, VarTable, InstMap0,
|
|
OrElseGoals0, OrElseGoals),
|
|
Shorthand = atomic_goal(AtomicGoalType, OuterVars, InnerVars,
|
|
OutputVars, MainGoal, OrElseGoals, OrElseInners)
|
|
),
|
|
GoalExpr = shorthand(Shorthand)
|
|
),
|
|
apply_instmap_delta(InstMapDelta, InstMap0, InstMap),
|
|
compute_goal_mode(ModuleInfo, VarTable, InstMapDelta, InstMap0, InstMap,
|
|
GoalInfo0, GoalInfo),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo).
|
|
|
|
:- pred compute_goal_modes_in_conj(module_info::in, var_table::in,
|
|
instmap::in, list(hlds_goal)::in, list(hlds_goal)::out) is det.
|
|
|
|
compute_goal_modes_in_conj(_, _, _, [], []).
|
|
compute_goal_modes_in_conj(ModuleInfo, VarTable, !.InstMap,
|
|
[Conjunct0 | Conjuncts0], [Conjunct | Conjuncts]) :-
|
|
compute_goal_modes_in_goal(ModuleInfo, VarTable, !InstMap,
|
|
Conjunct0, Conjunct),
|
|
compute_goal_modes_in_conj(ModuleInfo, VarTable, !.InstMap,
|
|
Conjuncts0, Conjuncts).
|
|
|
|
:- pred compute_goal_modes_in_disj(module_info::in, var_table::in,
|
|
instmap::in, list(hlds_goal)::in, list(hlds_goal)::out) is det.
|
|
|
|
compute_goal_modes_in_disj(_, _, _, [], []).
|
|
compute_goal_modes_in_disj(ModuleInfo, VarTable, InstMap0,
|
|
[Disjunct0 | Disjuncts0], [Disjunct | Disjuncts]) :-
|
|
compute_goal_modes_in_goal(ModuleInfo, VarTable, InstMap0, _InstMap,
|
|
Disjunct0, Disjunct),
|
|
compute_goal_modes_in_disj(ModuleInfo, VarTable, InstMap0,
|
|
Disjuncts0, Disjuncts).
|
|
|
|
:- pred compute_goal_modes_in_switch(module_info::in, var_table::in,
|
|
instmap::in, list(case)::in, list(case)::out) is det.
|
|
|
|
compute_goal_modes_in_switch(_, _, _, [], []).
|
|
compute_goal_modes_in_switch(ModuleInfo, VarTable, InstMap0,
|
|
[Case0 | Cases0], [Case | Cases]) :-
|
|
Case0 = case(MainConsId, OtherConsIds, Goal0),
|
|
compute_goal_modes_in_goal(ModuleInfo, VarTable, InstMap0, _InstMap,
|
|
Goal0, Goal),
|
|
Case = case(MainConsId, OtherConsIds, Goal),
|
|
compute_goal_modes_in_switch(ModuleInfo, VarTable, InstMap0,
|
|
Cases0, Cases).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred compute_goal_mode(module_info::in, var_table::in,
|
|
instmap_delta::in, instmap::in, instmap::in,
|
|
hlds_goal_info::in, hlds_goal_info::out) is det.
|
|
|
|
compute_goal_mode(ModuleInfo, VarTable, InstMapDelta, InstMap0, InstMap,
|
|
!GoalInfo) :-
|
|
( if instmap_delta_is_reachable(InstMapDelta) then
|
|
instmap_delta_changed_vars(InstMapDelta, Vars),
|
|
BoundVars0 = set_of_var.init,
|
|
BoundGroundedVars0 = set_of_var.init,
|
|
BoundNonGroundedVars0 = set_of_var.init,
|
|
list.foldl3(
|
|
record_var_if_bound(ModuleInfo, VarTable, InstMap0, InstMap),
|
|
set_of_var.to_sorted_list(Vars),
|
|
BoundVars0, BoundVars,
|
|
BoundGroundedVars0, BoundGroundedVars,
|
|
BoundNonGroundedVars0, BoundNonGroundedVars),
|
|
GoalMode = gm_reachable(BoundVars,
|
|
BoundGroundedVars, BoundNonGroundedVars)
|
|
else
|
|
GoalMode = gm_unreachable
|
|
),
|
|
goal_info_set_goal_mode(GoalMode, !GoalInfo).
|
|
|
|
:- pred record_var_if_bound(module_info::in, var_table::in,
|
|
instmap::in, instmap::in, prog_var::in,
|
|
set_of_progvar::in, set_of_progvar::out,
|
|
set_of_progvar::in, set_of_progvar::out,
|
|
set_of_progvar::in, set_of_progvar::out) is det.
|
|
|
|
record_var_if_bound(ModuleInfo, VarTable, InstMap0, InstMap, Var,
|
|
!BoundVars, !BoundGroundedVars, !BoundNonGroundedVars) :-
|
|
instmap_lookup_var(InstMap0, Var, Inst0),
|
|
instmap_lookup_var(InstMap, Var, Inst),
|
|
lookup_var_type(VarTable, Var, Type),
|
|
( if inst_matches_final_typed(ModuleInfo, Type, Inst0, Inst) then
|
|
true
|
|
else
|
|
set_of_var.insert(Var, !BoundVars),
|
|
( if inst_is_ground(ModuleInfo, Inst) then
|
|
set_of_var.insert(Var, !BoundGroundedVars)
|
|
else
|
|
set_of_var.insert(Var, !BoundNonGroundedVars)
|
|
)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- end_module hlds.goal_mode.
|
|
%-----------------------------------------------------------------------------%
|