Files
mercury/compiler/goal_mode.m
Zoltan Somogyi f7355f708b Move var_db and var_{name,type}_source to var_db.m.
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.
2022-08-19 10:44:39 +10:00

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.
%-----------------------------------------------------------------------------%