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.
687 lines
28 KiB
Mathematica
687 lines
28 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1994-2012 The University of Melbourne.
|
|
% Copyright (C) 2015 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.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: recompute_instmap_deltas.m.
|
|
% Main author: fjh.
|
|
%
|
|
% Most code transformations invalidate the instmap deltas in the goal_infos
|
|
% of nonatomic goals, and some transformations invalidate these in atomic goals
|
|
% as well. This module recomputes these instmap deltas.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module check_hlds.recompute_instmap_deltas.
|
|
:- interface.
|
|
|
|
:- import_module hlds.
|
|
:- 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.prog_data.
|
|
:- import_module parse_tree.var_table.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type recomp_atomics
|
|
---> recomp_atomics
|
|
; no_recomp_atomics.
|
|
|
|
% Use the instmap deltas for all the atomic subgoals to recompute
|
|
% the instmap deltas for all the non-atomic subgoals of a goal.
|
|
% Used to ensure that the instmap deltas remain valid after code has
|
|
% been re-arranged, e.g. by followcode. This also takes the module_info
|
|
% as input and output since it may need to insert new merge_insts
|
|
% into the merge_inst table. The first argument says whether the
|
|
% instmap_deltas for calls and deconstruction unifications
|
|
% should also recomputed. (For example, when common.m is run,
|
|
% we have to recompute the instmap deltas of atomic goals because
|
|
% some outputs of calls and deconstructions may have become non-local.)
|
|
%
|
|
:- pred recompute_instmap_delta_proc(recomp_atomics::in,
|
|
proc_info::in, proc_info::out, module_info::in, module_info::out) is det.
|
|
|
|
:- pred recompute_instmap_delta(recomp_atomics::in,
|
|
var_table::in, inst_varset::in, instmap::in, hlds_goal::in, hlds_goal::out,
|
|
module_info::in, module_info::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module check_hlds.inst_abstract_unify.
|
|
:- import_module check_hlds.inst_match.
|
|
:- import_module check_hlds.mode_util.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.prim_data.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.prog_mode.
|
|
:- import_module parse_tree.set_of_var.
|
|
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module maybe.
|
|
:- import_module require.
|
|
:- import_module term.
|
|
:- import_module varset.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type recompute_info
|
|
---> recompute_info(
|
|
ri_module_info :: module_info,
|
|
ri_inst_varset :: inst_varset
|
|
).
|
|
|
|
recompute_instmap_delta_proc(RecomputeAtomic, !ProcInfo, !ModuleInfo) :-
|
|
proc_info_get_initial_instmap(!.ModuleInfo, !.ProcInfo, InstMap0),
|
|
proc_info_get_var_table(!.ProcInfo, VarTable),
|
|
proc_info_get_goal(!.ProcInfo, Goal0),
|
|
proc_info_get_inst_varset(!.ProcInfo, InstVarSet),
|
|
recompute_instmap_delta(RecomputeAtomic, VarTable, InstVarSet, InstMap0,
|
|
Goal0, Goal, !ModuleInfo),
|
|
proc_info_set_goal(Goal, !ProcInfo).
|
|
|
|
recompute_instmap_delta(RecomputeAtomic, VarTable, InstVarSet, InstMap0,
|
|
Goal0, Goal, ModuleInfo0, ModuleInfo) :-
|
|
Params = recompute_params(RecomputeAtomic, VarTable),
|
|
RI0 = recompute_info(ModuleInfo0, InstVarSet),
|
|
recompute_instmap_delta_1(Params, InstMap0, _, Goal0, Goal, RI0, RI),
|
|
ModuleInfo = RI ^ ri_module_info.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type recompute_params
|
|
---> recompute_params(
|
|
recomp_atomics,
|
|
var_table
|
|
).
|
|
|
|
:- pred recompute_instmap_delta_1(recompute_params::in,
|
|
instmap::in, instmap_delta::out, hlds_goal::in, hlds_goal::out,
|
|
recompute_info::in, recompute_info::out) is det.
|
|
|
|
recompute_instmap_delta_1(Params, InstMap0, InstMapDelta, Goal0, Goal, !RI) :-
|
|
Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
|
|
(
|
|
GoalExpr0 = switch(Var, Det, Cases0),
|
|
( if
|
|
goal_info_has_feature(GoalInfo0, feature_mode_check_clauses_goal)
|
|
then
|
|
Cases = Cases0,
|
|
InstMapDelta1 = goal_info_get_instmap_delta(GoalInfo0)
|
|
else
|
|
NonLocals0 = goal_info_get_nonlocals(GoalInfo0),
|
|
recompute_instmap_delta_switch(Params, Var, NonLocals0, InstMap0,
|
|
InstMapDelta1, Cases0, Cases, !RI)
|
|
),
|
|
GoalExpr = switch(Var, Det, Cases)
|
|
;
|
|
GoalExpr0 = conj(ConjType, Conjuncts0),
|
|
recompute_instmap_delta_conj(Params, InstMap0, InstMapDelta1,
|
|
Conjuncts0, Conjuncts, !RI),
|
|
GoalExpr = conj(ConjType, Conjuncts)
|
|
;
|
|
GoalExpr0 = disj(Disjuncts0),
|
|
( if
|
|
goal_info_has_feature(GoalInfo0, feature_mode_check_clauses_goal)
|
|
then
|
|
Disjuncts = Disjuncts0,
|
|
InstMapDelta1 = goal_info_get_instmap_delta(GoalInfo0)
|
|
else
|
|
NonLocals0 = goal_info_get_nonlocals(GoalInfo0),
|
|
recompute_instmap_delta_disj(Params, NonLocals0, InstMap0,
|
|
InstMapDelta1, Disjuncts0, Disjuncts, !RI)
|
|
),
|
|
GoalExpr = disj(Disjuncts)
|
|
;
|
|
GoalExpr0 = negation(SubGoal0),
|
|
InstMapDelta0 = goal_info_get_instmap_delta(GoalInfo0),
|
|
( if instmap_delta_is_reachable(InstMapDelta0) then
|
|
instmap_delta_init_reachable(InstMapDelta1)
|
|
else
|
|
instmap_delta_init_unreachable(InstMapDelta1)
|
|
),
|
|
recompute_instmap_delta_1(Params, InstMap0, _, SubGoal0, SubGoal, !RI),
|
|
GoalExpr = negation(SubGoal)
|
|
;
|
|
GoalExpr0 = if_then_else(Vars, Cond0, Then0, Else0),
|
|
recompute_instmap_delta_1(Params, InstMap0, InstMapDeltaCond,
|
|
Cond0, Cond, !RI),
|
|
apply_instmap_delta(InstMapDeltaCond, InstMap0, InstMapCond),
|
|
recompute_instmap_delta_1(Params, InstMapCond, InstMapDeltaThen,
|
|
Then0, Then, !RI),
|
|
recompute_instmap_delta_1(Params, InstMap0, InstMapDeltaElse,
|
|
Else0, Else, !RI),
|
|
instmap_delta_apply_instmap_delta(InstMapDeltaCond, InstMapDeltaThen,
|
|
test_size, InstMapDeltaCondThen),
|
|
NonLocals0 = goal_info_get_nonlocals(GoalInfo0),
|
|
ModuleInfo0 = !.RI ^ ri_module_info,
|
|
Params = recompute_params(_, VarTable),
|
|
merge_instmap_delta(VarTable, NonLocals0, InstMap0,
|
|
InstMapDeltaElse, InstMapDeltaCondThen, InstMapDelta1,
|
|
ModuleInfo0, ModuleInfo),
|
|
!RI ^ ri_module_info := ModuleInfo,
|
|
GoalExpr = if_then_else(Vars, Cond, Then, Else)
|
|
;
|
|
GoalExpr0 = scope(Reason, SubGoal0),
|
|
( if Reason = from_ground_term(_, FGT) then
|
|
(
|
|
( FGT = from_ground_term_construct
|
|
; FGT = from_ground_term_deconstruct
|
|
),
|
|
SubGoal = SubGoal0,
|
|
SubGoal = hlds_goal(_, SubGoalInfo),
|
|
InstMapDelta1 = goal_info_get_instmap_delta(SubGoalInfo)
|
|
;
|
|
FGT = from_ground_term_initial,
|
|
unexpected($pred, "from_ground_term_initial")
|
|
;
|
|
FGT = from_ground_term_other,
|
|
recompute_instmap_delta_1(Params, InstMap0, InstMapDelta1,
|
|
SubGoal0, SubGoal, !RI)
|
|
)
|
|
else
|
|
recompute_instmap_delta_1(Params, InstMap0, InstMapDelta1,
|
|
SubGoal0, SubGoal, !RI)
|
|
),
|
|
GoalExpr = scope(Reason, SubGoal)
|
|
;
|
|
GoalExpr0 = generic_call(_Details, Vars, Modes, _, Detism),
|
|
Params = recompute_params(RecomputeAtomic, _),
|
|
(
|
|
RecomputeAtomic = no_recomp_atomics,
|
|
InstMapDelta1 = goal_info_get_instmap_delta(GoalInfo0)
|
|
;
|
|
RecomputeAtomic = recomp_atomics,
|
|
( if determinism_components(Detism, _, at_most_zero) then
|
|
instmap_delta_init_unreachable(InstMapDelta1)
|
|
else
|
|
ModuleInfo = !.RI ^ ri_module_info,
|
|
instmap_delta_from_mode_list(ModuleInfo, Vars, Modes,
|
|
InstMapDelta1)
|
|
)
|
|
),
|
|
GoalExpr = GoalExpr0
|
|
;
|
|
GoalExpr0 = plain_call(PredId, ProcId, ArgVars, _BI, _UC, _Name),
|
|
Params = recompute_params(RecomputeAtomic, _),
|
|
(
|
|
RecomputeAtomic = no_recomp_atomics,
|
|
InstMapDelta1 = goal_info_get_instmap_delta(GoalInfo0)
|
|
;
|
|
RecomputeAtomic = recomp_atomics,
|
|
recompute_instmap_delta_call(Params, PredId, ProcId, ArgVars,
|
|
InstMap0, InstMapDelta1, !RI)
|
|
),
|
|
GoalExpr = GoalExpr0
|
|
;
|
|
GoalExpr0 = unify(LHS, RHS0, UniMode0, Uni, Context),
|
|
(
|
|
RHS0 = rhs_lambda_goal(Purity, Groundness, PorF, EvalMethod,
|
|
LambdaNonLocals, ArgVarsModes, Det, SubGoal0),
|
|
ModuleInfo0 = !.RI ^ ri_module_info,
|
|
instmap.pre_lambda_update(ModuleInfo0, ArgVarsModes,
|
|
InstMap0, InstMap),
|
|
recompute_instmap_delta_1(Params, InstMap, _,
|
|
SubGoal0, SubGoal, !RI),
|
|
RHS = rhs_lambda_goal(Purity, Groundness, PorF, EvalMethod,
|
|
LambdaNonLocals, ArgVarsModes, Det, SubGoal)
|
|
;
|
|
( RHS0 = rhs_var(_)
|
|
; RHS0 = rhs_functor(_, _, _)
|
|
),
|
|
RHS = RHS0
|
|
),
|
|
Params = recompute_params(RecomputeAtomic, _),
|
|
(
|
|
RecomputeAtomic = no_recomp_atomics,
|
|
UniMode = UniMode0,
|
|
InstMapDelta1 = goal_info_get_instmap_delta(GoalInfo0)
|
|
;
|
|
RecomputeAtomic = recomp_atomics,
|
|
recompute_instmap_delta_unify(Uni, UniMode0, UniMode,
|
|
GoalInfo0, InstMap0, InstMapDelta1, !RI)
|
|
),
|
|
GoalExpr = unify(LHS, RHS, UniMode, Uni, Context)
|
|
;
|
|
GoalExpr0 = call_foreign_proc(_Attr, PredId, ProcId, Args, ExtraArgs,
|
|
_MTRC, _Impl),
|
|
Params = recompute_params(RecomputeAtomic, _),
|
|
(
|
|
RecomputeAtomic = no_recomp_atomics,
|
|
InstMapDelta1 = goal_info_get_instmap_delta(GoalInfo0)
|
|
;
|
|
RecomputeAtomic = recomp_atomics,
|
|
ArgVars = list.map(foreign_arg_var, Args),
|
|
recompute_instmap_delta_call(Params, PredId, ProcId, ArgVars,
|
|
InstMap0, InstMapDelta0, !RI),
|
|
(
|
|
ExtraArgs = [],
|
|
InstMapDelta1 = InstMapDelta0
|
|
;
|
|
ExtraArgs = [_ | _],
|
|
OldInstMapDelta = goal_info_get_instmap_delta(GoalInfo0),
|
|
ExtraArgVars = list.map(foreign_arg_var, ExtraArgs),
|
|
instmap_delta_restrict(set_of_var.list_to_set(ExtraArgVars),
|
|
OldInstMapDelta, ExtraArgsInstMapDelta),
|
|
instmap_delta_apply_instmap_delta(InstMapDelta0,
|
|
ExtraArgsInstMapDelta, large_base, InstMapDelta1)
|
|
)
|
|
),
|
|
GoalExpr = GoalExpr0
|
|
;
|
|
GoalExpr0 = shorthand(ShortHand0),
|
|
(
|
|
ShortHand0 = atomic_goal(GoalType, Outer, Inner, MaybeOutputVars,
|
|
MainGoal0, OrElseGoals0, OrElseInners),
|
|
Goals0 = [MainGoal0 | OrElseGoals0],
|
|
NonLocals0 = goal_info_get_nonlocals(GoalInfo0),
|
|
recompute_instmap_delta_disj(Params, NonLocals0, InstMap0,
|
|
InstMapDelta1, Goals0, Goals, !RI),
|
|
(
|
|
Goals = [],
|
|
unexpected($pred, "Goals = []")
|
|
;
|
|
Goals = [MainGoal | OrElseGoals]
|
|
),
|
|
ShortHand = atomic_goal(GoalType, Outer, Inner, MaybeOutputVars,
|
|
MainGoal, OrElseGoals, OrElseInners)
|
|
;
|
|
ShortHand0 = try_goal(MaybeIO, ResultVar, SubGoal0),
|
|
recompute_instmap_delta_1(Params, InstMap0, InstMapDelta1,
|
|
SubGoal0, SubGoal, !RI),
|
|
ShortHand = try_goal(MaybeIO, ResultVar, SubGoal)
|
|
;
|
|
ShortHand0 = bi_implication(_, _),
|
|
% These should have been expanded out by now.
|
|
unexpected($pred, "bi_implication")
|
|
),
|
|
GoalExpr = shorthand(ShortHand)
|
|
),
|
|
% If the initial instmap is unreachable, so is the final instmap.
|
|
( if instmap_is_unreachable(InstMap0) then
|
|
instmap_delta_init_unreachable(InstMapDelta)
|
|
else
|
|
NonLocals = goal_info_get_nonlocals(GoalInfo0),
|
|
instmap_delta_restrict(NonLocals, InstMapDelta1, InstMapDelta)
|
|
),
|
|
goal_info_set_instmap_delta(InstMapDelta, GoalInfo0, GoalInfo),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo).
|
|
|
|
%---------------------%
|
|
|
|
:- pred recompute_instmap_delta_conj(recompute_params::in,
|
|
instmap::in, instmap_delta::out,
|
|
list(hlds_goal)::in, list(hlds_goal)::out,
|
|
recompute_info::in, recompute_info::out) is det.
|
|
|
|
recompute_instmap_delta_conj(_, _, InstMapDelta, [], [], !RI) :-
|
|
instmap_delta_init_reachable(InstMapDelta).
|
|
recompute_instmap_delta_conj(Params, InstMap0, InstMapDelta,
|
|
[Goal0 | Goals0], [Goal | Goals], !RI) :-
|
|
recompute_instmap_delta_1(Params, InstMap0, InstMapDelta0,
|
|
Goal0, Goal, !RI),
|
|
apply_instmap_delta(InstMapDelta0, InstMap0, InstMap1),
|
|
recompute_instmap_delta_conj(Params, InstMap1, InstMapDelta1,
|
|
Goals0, Goals, !RI),
|
|
instmap_delta_apply_instmap_delta(InstMapDelta0, InstMapDelta1,
|
|
large_overlay, InstMapDelta).
|
|
|
|
%---------------------%
|
|
|
|
:- pred recompute_instmap_delta_disj(recompute_params::in,
|
|
set_of_progvar::in, instmap::in, instmap_delta::out,
|
|
list(hlds_goal)::in, list(hlds_goal)::out,
|
|
recompute_info::in, recompute_info::out) is det.
|
|
|
|
recompute_instmap_delta_disj(Params, NonLocals, InstMap, InstMapDelta,
|
|
Goals0, Goals, !RI) :-
|
|
recompute_instmap_delta_disjuncts(Params, NonLocals, InstMap,
|
|
Goals0, Goals, InstMapDeltas, !RI),
|
|
(
|
|
InstMapDeltas = [],
|
|
instmap_delta_init_unreachable(InstMapDelta)
|
|
;
|
|
InstMapDeltas = [_ | _],
|
|
Params = recompute_params(_, VarTable),
|
|
ModuleInfo0 = !.RI ^ ri_module_info,
|
|
merge_instmap_deltas(VarTable, NonLocals, InstMap, InstMapDeltas,
|
|
InstMapDelta, ModuleInfo0, ModuleInfo),
|
|
!RI ^ ri_module_info := ModuleInfo
|
|
).
|
|
|
|
:- pred recompute_instmap_delta_disjuncts(recompute_params::in,
|
|
set_of_progvar::in, instmap::in,
|
|
list(hlds_goal)::in, list(hlds_goal)::out, list(instmap_delta)::out,
|
|
recompute_info::in, recompute_info::out) is det.
|
|
|
|
recompute_instmap_delta_disjuncts(_Params, _NonLocals, _InstMap,
|
|
[], [], [], !RI).
|
|
recompute_instmap_delta_disjuncts(Params, NonLocals, InstMap,
|
|
[Goal0 | Goals0], [Goal | Goals],
|
|
[InstMapDelta | InstMapDeltas], !RI) :-
|
|
recompute_instmap_delta_1(Params, InstMap, InstMapDelta, Goal0, Goal, !RI),
|
|
recompute_instmap_delta_disjuncts(Params, NonLocals, InstMap,
|
|
Goals0, Goals, InstMapDeltas, !RI).
|
|
|
|
%---------------------%
|
|
|
|
:- pred recompute_instmap_delta_switch(recompute_params::in, prog_var::in,
|
|
set_of_progvar::in, instmap::in, instmap_delta::out,
|
|
list(case)::in, list(case)::out,
|
|
recompute_info::in, recompute_info::out) is det.
|
|
|
|
recompute_instmap_delta_switch(Params, Var, NonLocals, InstMap0, InstMapDelta,
|
|
Cases0, Cases, !RI) :-
|
|
recompute_instmap_delta_cases(Params, Var, NonLocals, InstMap0,
|
|
Cases0, Cases, InstMapDeltas, !RI),
|
|
(
|
|
InstMapDeltas = [],
|
|
instmap_delta_init_unreachable(InstMapDelta)
|
|
;
|
|
InstMapDeltas = [_ | _],
|
|
Params = recompute_params(_, VarTable),
|
|
ModuleInfo0 = !.RI ^ ri_module_info,
|
|
merge_instmap_deltas(VarTable, NonLocals, InstMap0, InstMapDeltas,
|
|
InstMapDelta, ModuleInfo0, ModuleInfo),
|
|
!RI ^ ri_module_info := ModuleInfo
|
|
).
|
|
|
|
:- pred recompute_instmap_delta_cases(recompute_params::in, prog_var::in,
|
|
set_of_progvar::in, instmap::in,
|
|
list(case)::in, list(case)::out, list(instmap_delta)::out,
|
|
recompute_info::in, recompute_info::out) is det.
|
|
|
|
recompute_instmap_delta_cases(_Params, _Var, _NonLocals, _InstMap,
|
|
[], [], [], !RI).
|
|
recompute_instmap_delta_cases(Params, Var, NonLocals, InstMap0,
|
|
[Case0 | Cases0], [Case | Cases],
|
|
[InstMapDelta | InstMapDeltas], !RI) :-
|
|
Case0 = case(MainConsId, OtherConsIds, Goal0),
|
|
Params = recompute_params(_, VarTable),
|
|
lookup_var_type(VarTable, Var, Type),
|
|
ModuleInfo0 = !.RI ^ ri_module_info,
|
|
bind_var_to_functors(Var, Type, MainConsId, OtherConsIds,
|
|
InstMap0, InstMap1, ModuleInfo0, ModuleInfo1),
|
|
!RI ^ ri_module_info := ModuleInfo1,
|
|
recompute_instmap_delta_1(Params, InstMap1, InstMapDelta0,
|
|
Goal0, Goal, !RI),
|
|
ModuleInfo2 = !.RI ^ ri_module_info,
|
|
instmap_delta_bind_var_to_functors(Var, Type, MainConsId, OtherConsIds,
|
|
InstMap0, InstMapDelta0, InstMapDelta, ModuleInfo2, ModuleInfo3),
|
|
!RI ^ ri_module_info := ModuleInfo3,
|
|
Case = case(MainConsId, OtherConsIds, Goal),
|
|
|
|
recompute_instmap_delta_cases(Params, Var, NonLocals, InstMap0,
|
|
Cases0, Cases, InstMapDeltas, !RI).
|
|
|
|
%---------------------%
|
|
|
|
:- pred recompute_instmap_delta_call(recompute_params::in,
|
|
pred_id::in, proc_id::in, list(prog_var)::in,
|
|
instmap::in, instmap_delta::out,
|
|
recompute_info::in, recompute_info::out) is det.
|
|
|
|
recompute_instmap_delta_call(Params, PredId, ProcId, ArgVars, InstMap,
|
|
InstMapDelta, !RI) :-
|
|
ModuleInfo0 = !.RI ^ ri_module_info,
|
|
module_info_pred_proc_info(ModuleInfo0, PredId, ProcId, _, ProcInfo),
|
|
proc_info_interface_determinism(ProcInfo, Detism),
|
|
( if determinism_components(Detism, _, at_most_zero) then
|
|
instmap_delta_init_unreachable(InstMapDelta)
|
|
else
|
|
proc_info_get_argmodes(ProcInfo, ArgModes0),
|
|
proc_info_get_inst_varset(ProcInfo, ProcInstVarSet),
|
|
InstVarSet0 = !.RI ^ ri_inst_varset,
|
|
rename_apart_inst_vars(InstVarSet0, ProcInstVarSet, InstVarSet,
|
|
ArgModes0, ArgModes1),
|
|
!RI ^ ri_inst_varset := InstVarSet,
|
|
mode_list_get_initial_insts(ModuleInfo0, ArgModes1, InitialInsts),
|
|
|
|
% Compute the inst_var substitution from the initial insts
|
|
% of the called procedure and the insts of the argument variables.
|
|
( if instmap_is_reachable(InstMap) then
|
|
map.init(InstVarSub0),
|
|
Params = recompute_params(_, VarTable),
|
|
compute_inst_var_sub(VarTable, InstMap, ArgVars, InitialInsts,
|
|
InstVarSub0, InstVarSub, ModuleInfo0, ModuleInfo1),
|
|
|
|
% Apply the inst_var substitution to the argument modes.
|
|
mode_list_apply_substitution(InstVarSub, ArgModes1, ArgModes2),
|
|
|
|
% Calculate the final insts of the argument variables from their
|
|
% initial insts and the final insts of the called procedure
|
|
% (with inst_var substitutions applied).
|
|
recompute_instmap_delta_call_args(ArgVars, InstMap,
|
|
ArgModes2, ArgModes, ModuleInfo1, ModuleInfo),
|
|
!RI ^ ri_module_info := ModuleInfo
|
|
else
|
|
list.length(ArgVars, NumArgVars),
|
|
list.duplicate(NumArgVars, from_to_mode(not_reached, not_reached),
|
|
ArgModes),
|
|
ModuleInfo = ModuleInfo0
|
|
),
|
|
instmap_delta_from_mode_list(ModuleInfo, ArgVars, ArgModes,
|
|
InstMapDelta)
|
|
).
|
|
|
|
:- pred compute_inst_var_sub(var_table::in, instmap::in,
|
|
list(prog_var)::in, list(mer_inst)::in,
|
|
inst_var_sub::in, inst_var_sub::out,
|
|
module_info::in, module_info::out) is det.
|
|
|
|
compute_inst_var_sub(_, _, [], [], !Sub, !ModuleInfo).
|
|
compute_inst_var_sub(_, _, [_ | _], [], !Sub, !ModuleInfo) :-
|
|
unexpected($pred, "length mismatch").
|
|
compute_inst_var_sub(_, _, [], [_ | _], !Sub, !ModuleInfo) :-
|
|
unexpected($pred, "length mismatch").
|
|
compute_inst_var_sub(VarTable, InstMap, [ArgVar | ArgVars], [Inst | Insts],
|
|
!Sub, !ModuleInfo) :-
|
|
% This is similar to modecheck_var_has_inst.
|
|
SaveModuleInfo = !.ModuleInfo,
|
|
SaveSub = !.Sub,
|
|
instmap_lookup_var(InstMap, ArgVar, ArgInst),
|
|
lookup_var_type(VarTable, ArgVar, Type),
|
|
( if inst_matches_initial_sub(Type, ArgInst, Inst, !ModuleInfo, !Sub) then
|
|
true
|
|
else
|
|
% error("compute_inst_var_sub: " ++
|
|
% ++ "inst_matches_initial failed")
|
|
% XXX We shouldn't ever get here, but unfortunately
|
|
% the mode system currently has several problems (most
|
|
% noticeably lack of alias tracking for unique modes)
|
|
% which mean inst_matches_initial can sometimes fail here.
|
|
!:ModuleInfo = SaveModuleInfo,
|
|
!:Sub = SaveSub
|
|
),
|
|
compute_inst_var_sub(VarTable, InstMap, ArgVars, Insts, !Sub, !ModuleInfo).
|
|
|
|
:- pred recompute_instmap_delta_call_args(list(prog_var)::in, instmap::in,
|
|
list(mer_mode)::in, list(mer_mode)::out, module_info::in, module_info::out)
|
|
is det.
|
|
|
|
recompute_instmap_delta_call_args([], _, [], [], !ModuleInfo).
|
|
recompute_instmap_delta_call_args([_ | _], _, [], _, !ModuleInfo) :-
|
|
unexpected($pred, "length mismatch").
|
|
recompute_instmap_delta_call_args([], _, [_ | _], _, !ModuleInfo) :-
|
|
unexpected($pred, "length mismatch").
|
|
recompute_instmap_delta_call_args([Arg | Args], InstMap, [Mode0 | Modes0],
|
|
[Mode | Modes], !ModuleInfo) :-
|
|
% This is similar to modecheck_set_var_inst.
|
|
instmap_lookup_var(InstMap, Arg, ArgInst0),
|
|
mode_get_insts(!.ModuleInfo, Mode0, _, FinalInst),
|
|
( if
|
|
% The is_dead allows abstractly_unify_inst to succeed when
|
|
% some parts of ArgInst0 and the corresponding parts of FinalInst
|
|
% are free.
|
|
% XXX There should be a better way to communicate that information.
|
|
abstractly_unify_inst(is_dead, ArgInst0, FinalInst,
|
|
fake_unify, UnifyInst, _, !ModuleInfo)
|
|
then
|
|
Mode = from_to_mode(ArgInst0, UnifyInst)
|
|
else
|
|
unexpected($pred, "unify_inst failed")
|
|
),
|
|
recompute_instmap_delta_call_args(Args, InstMap, Modes0, Modes,
|
|
!ModuleInfo).
|
|
|
|
%---------------------%
|
|
|
|
:- pred recompute_instmap_delta_unify(unification::in, unify_mode::in,
|
|
unify_mode::out, hlds_goal_info::in, instmap::in, instmap_delta::out,
|
|
recompute_info::in, recompute_info::out) is det.
|
|
|
|
recompute_instmap_delta_unify(Unification, UniMode0, UniMode, GoalInfo,
|
|
InstMap, InstMapDelta, !RI) :-
|
|
% Deconstructions are the only types of unifications that can require
|
|
% updating of the instmap_delta after simplify.m has been run.
|
|
% Type specialization may require constructions of type-infos,
|
|
% typeclass-infos or predicate constants to be added to the
|
|
% instmap_delta.
|
|
ModuleInfo0 = !.RI ^ ri_module_info,
|
|
(
|
|
Unification = deconstruct(LHSVar, _ConsId, RHSVars, ArgModes,
|
|
_, _CanCGC),
|
|
|
|
% Get the final inst of the deconstructed var, which will be the same
|
|
% as in the old instmap.
|
|
|
|
OldInstMapDelta = goal_info_get_instmap_delta(GoalInfo),
|
|
instmap_lookup_var(InstMap, LHSVar, LHSInitialInst),
|
|
( if instmap_delta_search_var(OldInstMapDelta, LHSVar, DeltaInst) then
|
|
% Inlining can result in situations where the initial inst
|
|
% (from procedure 1) can decide that a variable must be bound
|
|
% to one set of function symbols, while the instmap delta from
|
|
% a later unification (from procedure 2) can say that it is bound
|
|
% to a different, non-overlapping set of function symbols.
|
|
%
|
|
% The is_dead allows abstractly_unify_inst to succeed when some
|
|
% parts of InitialInst and the corresponding parts of DeltaInst
|
|
% are free.
|
|
% XXX There should be a better way to communicate that information.
|
|
( if
|
|
abstractly_unify_inst(is_dead, LHSInitialInst, DeltaInst,
|
|
fake_unify, LHSFinalInstPrime, _Detism,
|
|
ModuleInfo0, ModuleInfo1)
|
|
then
|
|
LHSFinalInst = LHSFinalInstPrime,
|
|
ModuleInfo = ModuleInfo1,
|
|
!RI ^ ri_module_info := ModuleInfo
|
|
else
|
|
unexpected($pred, "abstractly_unify_inst failed")
|
|
)
|
|
else
|
|
% It wasn't in the instmap_delta, so the inst didn't change.
|
|
LHSFinalInst = LHSInitialInst,
|
|
ModuleInfo = ModuleInfo0
|
|
),
|
|
LHSTuple = var_init_final_insts(LHSVar, LHSInitialInst, LHSFinalInst),
|
|
pair_arg_vars_with_rhs_insts(RHSVars, ArgModes, RHSTuples),
|
|
instmap_delta_from_var_init_final_insts(ModuleInfo,
|
|
[LHSTuple | RHSTuples], InstMapDelta),
|
|
UniMode = UniMode0
|
|
;
|
|
Unification = construct(Var, ConsId, Args, _, _, _, _),
|
|
( if
|
|
NonLocals = goal_info_get_nonlocals(GoalInfo),
|
|
set_of_var.member(NonLocals, Var),
|
|
OldInstMapDelta = goal_info_get_instmap_delta(GoalInfo),
|
|
not instmap_delta_search_var(OldInstMapDelta, Var, _),
|
|
MaybeInst = cons_id_to_shared_inst(ModuleInfo0, ConsId,
|
|
list.length(Args)),
|
|
MaybeInst = yes(Inst)
|
|
then
|
|
UniMode = UniMode0,
|
|
instmap_delta_init_reachable(InstMapDelta0),
|
|
instmap_delta_set_var(Var, Inst, InstMapDelta0, InstMapDelta)
|
|
else
|
|
InstMapDelta = goal_info_get_instmap_delta(GoalInfo),
|
|
UniMode = UniMode0
|
|
)
|
|
;
|
|
( Unification = assign(_, _)
|
|
; Unification = simple_test(_, _)
|
|
; Unification = complicated_unify(_, _, _)
|
|
),
|
|
InstMapDelta = goal_info_get_instmap_delta(GoalInfo),
|
|
UniMode = UniMode0
|
|
).
|
|
|
|
:- pred pair_arg_vars_with_rhs_insts(list(prog_var)::in, list(unify_mode)::in,
|
|
list(var_init_final_insts)::out) is det.
|
|
|
|
pair_arg_vars_with_rhs_insts([], [], []).
|
|
pair_arg_vars_with_rhs_insts([], [_ | _], _) :-
|
|
unexpected($pred, "mismatched list lengths").
|
|
pair_arg_vars_with_rhs_insts([_ | _], [], _) :-
|
|
unexpected($pred, "mismatched list lengths").
|
|
pair_arg_vars_with_rhs_insts([RHSVar | RHSVars], [UnifyMode | UnifyModes],
|
|
[Tuple | Tuples]) :-
|
|
UnifyMode = unify_modes_li_lf_ri_rf(_, _, InitRHS, FinalRHS),
|
|
Tuple = var_init_final_insts(RHSVar, InitRHS, FinalRHS),
|
|
pair_arg_vars_with_rhs_insts(RHSVars, UnifyModes, Tuples).
|
|
|
|
% For a builtin constructor, return the inst of the constructed term.
|
|
% Handling user-defined constructors properly would require running
|
|
% mode analysis again.
|
|
%
|
|
:- func cons_id_to_shared_inst(module_info, cons_id, int) = maybe(mer_inst).
|
|
|
|
cons_id_to_shared_inst(ModuleInfo, ConsId, NumArgs) = MaybeInst :-
|
|
(
|
|
( ConsId = cons(_, _, _)
|
|
; ConsId = tuple_cons(_)
|
|
),
|
|
MaybeInst = no
|
|
;
|
|
% Note that before the change that introduced the char_const functor,
|
|
% we used to handle character constants as user-defined cons_ids.
|
|
( ConsId = some_int_const(_)
|
|
; ConsId = float_const(_)
|
|
; ConsId = char_const(_)
|
|
; ConsId = string_const(_)
|
|
),
|
|
MaybeInst = yes(bound(shared, inst_test_results_fgtc,
|
|
[bound_functor(ConsId, [])]))
|
|
;
|
|
ConsId = impl_defined_const(_),
|
|
unexpected($pred, "impl_defined_const")
|
|
;
|
|
ConsId = closure_cons(PredProcId, _),
|
|
module_info_pred_proc_info(ModuleInfo,
|
|
unshroud_pred_proc_id(PredProcId), PredInfo, ProcInfo),
|
|
PorF = pred_info_is_pred_or_func(PredInfo),
|
|
proc_info_interface_determinism(ProcInfo, Det),
|
|
proc_info_get_argmodes(ProcInfo, ProcArgModes),
|
|
list.det_drop(NumArgs, ProcArgModes, Modes),
|
|
Inst = ground(shared, higher_order(pred_inst_info(PorF, Modes,
|
|
arg_reg_types_unset, Det))),
|
|
MaybeInst = yes(Inst)
|
|
;
|
|
( ConsId = type_ctor_info_const(_, _, _)
|
|
; ConsId = base_typeclass_info_const(_, _, _, _)
|
|
; ConsId = type_info_cell_constructor(_)
|
|
; ConsId = typeclass_info_cell_constructor
|
|
; ConsId = type_info_const(_)
|
|
; ConsId = typeclass_info_const(_)
|
|
; ConsId = ground_term_const(_, _)
|
|
; ConsId = tabling_info_const(_)
|
|
; ConsId = table_io_entry_desc(_)
|
|
; ConsId = deep_profiling_proc_layout(_)
|
|
),
|
|
MaybeInst = yes(ground(shared, none_or_default_func))
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module check_hlds.recompute_instmap_deltas.
|
|
%---------------------------------------------------------------------------%
|