Files
mercury/compiler/simplify.m
Simon Taylor 1839ebb663 Module qualification of constructors.
Estimated hours taken: 15

Module qualification of constructors.

compiler/modes.m
compiler/unique_modes.m
compiler/modecheck_unify.m
compiler/modecheck_call.m
	Enable propagate_type_info_into_modes.
	Use type information to module qualify cons_ids.

compiler/mode_util.m
	Use propagate_type_information_into_modes to module qualify cons_ids
	in bound insts.
	typed_ground/2 and free/1 insts are not yet generated, since they
	are not yet used anywhere.
	Avoid expanding insts when propagating type information, since
	that is not yet useful.
	I still need to fix the handling of
		inst_matches_{initial, final, binding}(
			ground(_, _), bound(_, [all_functors_in_the_type]))

compiler/typecheck.m
	Don't assume a module qualified cons_id is a function call
	or higher-order pred constant.

compiler/modes.m
compiler/unique_modes.m
compiler/modecheck_unify.m
compiler/instmap.m
compiler/inst_match.m
	Remove some unnecessary conversion between cons_ids and consts.

compiler/typecheck.m
compiler/mode_errors.m
	Strip builtin qualifiers from cons_ids.

compiler/mercury_to_mercury.m
	Output module qualified cons_ids.

compiler/prog_io.m
compiler/prog_io_util.m
	Module qualify constructors in type definitions.
	Parse qualified cons_ids in bound insts.

compiler/hlds_data.m
	Remove cons_id_to_const/3, since it doesn't make much sense any more.
	Add cons_id_arity/2 and cons_id_and_args_to_term/3.

compiler/make_hlds.m
	Add both qualified and unqualified versions of each cons_id to
	the cons_table.

compiler/det_util.m
	Handle module qualified cons_ids in det_util__interpret_unify.

compiler/code_util.m
	Remove some dead code in code_util__cons_id_to_tag to do with
	tags for higher-order terms. Don't assume module qualified
	cons_ids are higher-order pred constants.

compiler/polymorphism.m
	Module qualify type_info cons_ids.
1997-02-17 01:27:10 +00:00

1360 lines
48 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 1995 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.
%-----------------------------------------------------------------------------%
%
% Main author: zs.
%
% The two jobs of the simplification module are
%
% to find and exploit opportunities for simplifying the internal form
% of the program, both to optimize the code and to massage the code
% into a form the code generator will accept, and
%
% to warn the programmer about any constructs that are so simple that
% they should not have been included in the program in the first place.
%
% Simplification is done in two passes. The first pass performs common
% structure elimination and branch merging. The second pass performs
% excess assignment elimination and cleans up the code after the first pass.
% Two passes are required because the goal must be requantified after the
% optimizations in common.m are run so that excess assignment elimination
% works properly.
%
%-----------------------------------------------------------------------------%
:- module simplify.
:- interface.
:- import_module common, hlds_pred, det_report, det_util.
:- import_module list, io.
:- pred simplify__proc(simplify, pred_id, proc_id, module_info, module_info,
proc_info, proc_info, int, int, io__state, io__state).
:- mode simplify__proc(in, in, in, in, out, in, out, out, out, di, uo) is det.
:- pred simplify__goal(hlds__goal, hlds__goal,
simplify_info, simplify_info).
:- mode simplify__goal(in, out, in, out) is det.
:- pred simplify_info_init(det_info, simplify, instmap,
varset, map(var, type), simplify_info).
:- mode simplify_info_init(in, in, in, in, in, out) is det.
:- type simplify_info.
:- type simplify
---> simplify(
bool, % --warn-simple-code
bool, % --warn-duplicate-calls
bool, % run things that should be done once only
bool, % attempt to merge adjacent switches
bool, % common subexpression elimination
bool, % remove excess assignment unifications
bool % optimize duplicate calls
).
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module hlds_out.
:- import_module code_aux, det_report, det_analysis, follow_code, goal_util.
:- import_module hlds_module, hlds_goal, hlds_data, instmap, inst_match.
:- import_module globals, options, passes_aux, prog_data, mode_util, type_util.
:- import_module code_util, quantification, modes.
:- import_module bool, set, map, require, std_util, term, varset.
%-----------------------------------------------------------------------------%
simplify__proc(Simplify, PredId, ProcId, ModuleInfo0, ModuleInfo,
Proc0, Proc, WarnCnt, ErrCnt, State0, State) :-
globals__io_get_globals(Globals, State0, State1),
det_info_init(ModuleInfo0, PredId, ProcId, Globals, DetInfo),
proc_info_get_initial_instmap(Proc0, ModuleInfo0, InstMap0),
proc_info_variables(Proc0, VarSet0),
proc_info_vartypes(Proc0, VarTypes0),
simplify_info_init(DetInfo, Simplify, InstMap0,
VarSet0, VarTypes0, Info0),
write_pred_progress_message("% Simplifying ", PredId, ModuleInfo0,
State1, State2),
( simplify_do_common(Info0) ->
Simplify = simplify(Warn, WarnCalls, Once,
Switch, _, Excess, Calls),
% On the first pass do common structure elimination and
% branch merging.
simplify_info_set_simplify(Info0,
simplify(Warn, WarnCalls, no, Switch, yes, no, Calls),
Info1),
simplify__proc_2(Proc0, Proc1, ModuleInfo0, ModuleInfo1,
Info1, Info2, State2, State3),
simplify_info_get_msgs(Info2, Msgs1),
proc_info_variables(Proc1, VarSet1),
proc_info_vartypes(Proc1, VarTypes1),
simplify_info_init(DetInfo,
simplify(Warn, WarnCalls, Once, no, no, Excess, no),
InstMap0, VarSet1, VarTypes1, Info3),
simplify_info_set_msgs(Info3, Msgs1, Info4),
%proc_info_goal(Proc1, OutGoal),
%hlds_out__write_goal(OutGoal, ModuleInfo1, VarSet1, yes,
% 2, ".", State3, State4)
State4 = State3
;
Info4 = Info0,
Proc1 = Proc0,
ModuleInfo1 = ModuleInfo0,
State4 = State2
),
% On the second pass do excess assignment elimination and
% some cleaning up after the common structure and branch
% merging pass.
simplify__proc_2(Proc1, Proc, ModuleInfo1, ModuleInfo,
Info4, Info, State4, State5),
simplify_info_get_msgs(Info, Msgs2),
set__to_sorted_list(Msgs2, Msgs),
( simplify_do_warn(Info) ->
det_report_msgs(Msgs, ModuleInfo, WarnCnt,
ErrCnt, State5, State)
;
WarnCnt = 0,
ErrCnt = 0,
State = State5
).
:- pred simplify__proc_2(proc_info::in, proc_info::out, module_info::in,
module_info::out, simplify_info::in, simplify_info::out,
io__state::di, io__state::uo) is det.
simplify__proc_2(Proc0, Proc, ModuleInfo0, ModuleInfo,
Info0, Info, State0, State) :-
proc_info_goal(Proc0, Goal0),
simplify__goal(Goal0, Goal, Info0, Info),
simplify_info_get_varset(Info, VarSet),
simplify_info_get_var_types(Info, VarTypes),
proc_info_set_goal(Proc0, Goal, Proc1),
proc_info_set_variables(Proc1, VarSet, Proc2),
proc_info_set_vartypes(Proc2, VarTypes, Proc3),
( simplify_info_requantify(Info) ->
requantify_proc(Proc3, Proc4),
( simplify_info_recompute_atomic(Info) ->
RecomputeAtomic = yes
;
RecomputeAtomic = no
),
proc_info_goal(Proc4, Goal2),
proc_info_get_initial_instmap(Proc4,
ModuleInfo0, InstMap0),
recompute_instmap_delta(RecomputeAtomic, Goal2, Goal3,
InstMap0, ModuleInfo0, ModuleInfo),
proc_info_set_goal(Proc4, Goal3, Proc),
State = State0
;
Proc = Proc3,
ModuleInfo = ModuleInfo0,
State = State0
).
%-----------------------------------------------------------------------------%
simplify__goal(Goal0 - GoalInfo0, Goal - GoalInfo, Info0, Info) :-
simplify_info_get_det_info(Info0, DetInfo),
goal_info_get_determinism(GoalInfo0, Detism),
simplify_info_get_module_info(Info0, ModuleInfo),
(
%
% if --no-fully-strict,
% replace goals with determinism failure with `fail'.
% XXX we should warn about this (if the goal wasn't `fail')
%
Detism = failure,
( det_info_get_fully_strict(DetInfo, no)
; code_aux__goal_cannot_loop(ModuleInfo, Goal0 - GoalInfo0)
)
->
map__init(Empty),
Goal1 = disj([], Empty),
GoalInfo1 = GoalInfo0 % need we massage this?
;
%
% if --no-fully-strict,
% replace goals which cannot fail and have no
% output variables with `true'.
% However, we don't do this for erroneous goals,
% since these may occur in conjunctions where there
% are no producers for some variables, and the
% code generator would fail for these.
% XXX we should warn about this (if the goal wasn't `true')
%
determinism_components(Detism, cannot_fail, MaxSoln),
MaxSoln \= at_most_zero,
goal_info_get_instmap_delta(GoalInfo0, InstMapDelta),
goal_info_get_nonlocals(GoalInfo0, NonLocalVars),
simplify_info_get_instmap(Info0, InstMap0),
det_no_output_vars(NonLocalVars, InstMap0, InstMapDelta,
DetInfo),
( det_info_get_fully_strict(DetInfo, no)
; code_aux__goal_cannot_loop(ModuleInfo, Goal0 - GoalInfo0)
)
->
Goal1 = conj([]),
GoalInfo1 = GoalInfo0 % need we massage this?
;
Goal1 = Goal0,
GoalInfo1 = GoalInfo0
),
simplify_info_maybe_clear_structs(before, Goal1 - GoalInfo1,
Info0, Info1),
simplify__goal_2(Goal1, GoalInfo1, Goal, GoalInfo, Info1, Info2),
simplify_info_maybe_clear_structs(after, Goal - GoalInfo, Info2, Info).
%-----------------------------------------------------------------------------%
:- pred simplify__goal_2(hlds__goal_expr, hlds__goal_info, hlds__goal_expr,
hlds__goal_info, simplify_info, simplify_info).
:- mode simplify__goal_2(in, in, out, out, in, out) is det.
simplify__goal_2(conj(Goals0), GoalInfo0, Goal, GoalInfo0, Info0, Info) :-
simplify_info_reset_branch_info(Info0, Info1, PostBranchInstMaps),
simplify_info_get_instmap(Info1, InstMap0),
simplify__conj(Goals0, [], Goals, GoalInfo0, Info1, Info2),
simplify_info_set_branch_info(Info2, PostBranchInstMaps, Info3),
simplify_info_set_instmap(Info3, InstMap0, Info),
( Goals = [SingleGoal] ->
% a singleton conjunction is equivalent to the goal itself
SingleGoal = Goal - _
;
%
% Conjunctions that cannot produce solutions may nevertheless
% contain nondet and multidet goals. If this happens, the
% conjunction is put inside a `some' to appease the code
% generator.
%
goal_info_get_determinism(GoalInfo0, Detism),
(
simplify_do_once(Info),
determinism_components(Detism, CanFail, at_most_zero),
simplify__contains_multisoln_goal(Goals)
->
determinism_components(InnerDetism,
CanFail, at_most_many),
goal_info_set_determinism(GoalInfo0,
InnerDetism, InnerInfo),
InnerGoal = conj(Goals) - InnerInfo,
Goal = some([], InnerGoal)
;
Goal = conj(Goals)
)
).
simplify__goal_2(disj(Disjuncts0, SM), GoalInfo,
Goal, GoalInfo, Info0, Info) :-
( Disjuncts0 = [] ->
Goal = disj([], SM),
Info = Info0
; Disjuncts0 = [SingleGoal0] ->
% a singleton disjunction is equivalent to the goal itself
simplify__goal(SingleGoal0, Goal - _, Info0, Info)
;
simplify__disj(Disjuncts0, Disjuncts, [], InstMaps,
Info0, Info0, Info1),
simplify_info_create_branch_info(Info0, Info1, InstMaps, Info),
(
/****
XXX This optimization is not correct, see comment below
at the definition of fixup_disj
goal_info_get_determinism(GoalInfo, Detism),
determinism_components(Detism, _CanFail, MaxSoln),
MaxSoln \= at_most_many
->
goal_info_get_instmap_delta(GoalInfo, DeltaInstMap),
goal_info_get_nonlocals(GoalInfo, NonLocalVars),
(
det_no_output_vars(NonLocalVars, InstMap0,
DeltaInstMap, DetInfo)
->
OutputVars = no
;
OutputVars = yes
),
simplify__fixup_disj(Disjuncts, Detism, OutputVars,
GoalInfo, SM, InstMap0, DetInfo, Goal,
MsgsA, Msgs)
;
****/
Goal = disj(Disjuncts, SM)
)
).
simplify__goal_2(switch(Var, SwitchCanFail, Cases0, SM),
GoalInfo0, Goal, GoalInfo, Info0, Info) :-
simplify_info_get_instmap(Info0, InstMap0),
simplify_info_get_module_info(Info0, ModuleInfo),
instmap__lookup_var(InstMap0, Var, VarInst),
( inst_is_bound_to_functors(ModuleInfo, VarInst, Functors) ->
functors_to_cons_ids(Functors, ConsIds0),
list__sort(ConsIds0, ConsIds),
delete_unreachable_cases(Cases0, ConsIds, Cases1),
MaybeConsIds = yes(ConsIds)
;
Cases1 = Cases0,
MaybeConsIds = no
),
( Cases1 = [] ->
% An empty switch always fails.
Goal = disj([], SM),
Info = Info0,
goal_info_init(GoalInfo1),
goal_info_set_determinism(GoalInfo1, failure, GoalInfo2),
instmap_delta_init_unreachable(Delta),
goal_info_set_instmap_delta(GoalInfo2, Delta, GoalInfo)
; Cases1 = [case(ConsId, SingleGoal0)] ->
% a singleton switch is equivalent to the goal itself with
% a possibly can_fail unification with the functor on the front.
cons_id_arity(ConsId, Arity),
(
SwitchCanFail = can_fail,
MaybeConsIds \= yes([ConsId])
->
simplify__create_test_unification(Var, ConsId, Arity,
UnifyGoal, Info0, Info1),
conjoin_goals(UnifyGoal, SingleGoal0, Goal1)
;
% The var can only be bound to this cons_id, so
% a test is unnecessary.
Goal1 = SingleGoal0,
Info1 = Info0
),
simplify__goal(Goal1, Goal - GoalInfo, Info1, Info)
;
GoalInfo = GoalInfo0,
simplify__switch(Var, Cases1, Cases, [], InstMaps,
Info0, Info0, Info1),
simplify_info_create_branch_info(Info0, Info1, InstMaps, Info),
Goal = switch(Var, SwitchCanFail, Cases, SM)
).
simplify__goal_2(Goal0, GoalInfo, Goal, GoalInfo, Info0, Info) :-
Goal0 = higher_order_call(Closure, Args, _, Modes, Det),
( simplify_do_calls(Info0) ->
common__optimise_higher_order_call(Closure, Args, Modes, Det,
Goal0, GoalInfo, Goal, Info0, Info)
;
Goal = Goal0,
Info = Info0
).
simplify__goal_2(Goal0, GoalInfo, Goal, GoalInfo, Info0, Info) :-
Goal0 = call(PredId, ProcId, Args, IsBuiltin, _, _),
%
% check for calls to predicates with `pragma obsolete' declarations
%
(
simplify_do_warn(Info0),
simplify_info_get_module_info(Info0, ModuleInfo),
module_info_pred_info(ModuleInfo, PredId, PredInfo),
pred_info_get_marker_list(PredInfo, Markers),
list__member(request(obsolete), Markers)
->
simplify_info_add_msg(Info0, warn_obsolete(PredId, GoalInfo),
Info1)
;
Info1 = Info0
),
%
% Check for recursive calls with the same input arguments,
% and warn about them (since they will lead to infinite loops).
%
(
simplify_do_warn(Info1),
%
% Is this a (directly) recursive call,
% i.e. is the procedure being called the same as the
% procedure we're analyzing?
%
simplify_info_get_det_info(Info1, DetInfo),
det_info_get_pred_id(DetInfo, PredId),
det_info_get_proc_id(DetInfo, ProcId),
%
% Don't count inline builtins.
% (The compiler generates code for builtins that looks
% recursive, so that you can take their address, but since
% the recursive call actually expands into inline
% instructions, so it's not infinite recursion.)
%
IsBuiltin \= inline_builtin,
%
% Are the input arguments the same (or equivalent)?
%
simplify_info_get_module_info(Info1, ModuleInfo1),
module_info_pred_proc_info(ModuleInfo1, PredId, ProcId,
_PredInfo1, ProcInfo1),
proc_info_headvars(ProcInfo1, HeadVars),
proc_info_argmodes(ProcInfo1, ArgModes),
simplify_info_get_common_info(Info1, CommonInfo1),
simplify__input_args_are_equiv(Args, HeadVars, ArgModes,
CommonInfo1, ModuleInfo1)
->
simplify_info_add_msg(Info1, warn_infinite_recursion(GoalInfo),
Info2)
;
Info2 = Info1
),
%
% check for duplicate calls to the same procedure
%
( simplify_do_calls(Info2) ->
common__optimise_call(PredId, ProcId, Args, Goal0, GoalInfo,
Goal, Info2, Info)
;
Goal = Goal0,
Info = Info2
).
simplify__goal_2(Goal0, GoalInfo0, Goal, GoalInfo, Info0, Info) :-
Goal0 = unify(LT0, RT0, M, U0, C),
(
RT0 = lambda_goal(PredOrFunc, Vars, Modes, LambdaDeclaredDet,
LambdaGoal0)
->
simplify_info_get_common_info(Info0, Common),
simplify__goal(LambdaGoal0, LambdaGoal, Info0, Info1),
simplify_info_set_common_info(Info1, Common, Info),
RT = lambda_goal(PredOrFunc, Vars, Modes, LambdaDeclaredDet,
LambdaGoal),
Goal = unify(LT0, RT, M, U0, C),
GoalInfo = GoalInfo0
;
simplify_do_common(Info0)
->
common__optimise_unification(U0, LT0, RT0, M, C,
Goal0, GoalInfo0, Goal, GoalInfo, Info0, Info)
;
Goal = Goal0,
GoalInfo = GoalInfo0,
Info = Info0
).
% (A -> B ; C) is logically equivalent to (A, B ; ~A, C).
% If the determinism of A means that one of these disjuncts
% cannot succeed, then we replace the if-then-else with the
% other disjunct. (We could also eliminate A, but we leave
% that to the recursive invocations.)
%
% The conjunction operator in the remaining disjunct ought to be
% a sequential conjunction, because Mercury's if-then-else always
% guarantees sequentiality, whereas conjunction only guarantees
% sequentiality if the --no-reorder-conj option is enabled.
%
% However, currently reordering is only done in mode analysis,
% not in the code generator, so we don't yet need a sequential
% conjunction construct. This will change when constraint pushing
% is finished, or when we start doing coroutining.
simplify__goal_2(if_then_else(Vars, Cond0, Then0, Else0, SM),
GoalInfo, Goal, GoalInfo, Info0, Info) :-
Cond0 = _ - CondInfo0,
goal_info_get_determinism(CondInfo0, CondDetism),
determinism_components(CondDetism, CondCanFail, _CondSolns),
( CondCanFail = cannot_fail ->
goal_to_conj_list(Cond0, CondList),
goal_to_conj_list(Then0, ThenList),
list__append(CondList, ThenList, List),
simplify__goal(conj(List) - GoalInfo, Goal - _,
Info0, Info1),
simplify_info_add_msg(Info1, ite_cond_cannot_fail(GoalInfo),
Info)
/*********
The following optimization is disabled, because it is
buggy (see the XXX below). It's not important, since
most of these cases will be optimized by modes.m anyway.
; CondSolns = at_most_zero ->
% Optimize away the condition and the `then' part.
goal_to_conj_list(Else0, ElseList),
% XXX Using CondInfo without updating the determinism is a bug.
% We should probably update other goal_info fields as well,
% e.g. the instmap_delta.
List = [not(Cond0) - CondInfo | ElseList],
simplify__goal(conj(List) - GoalInfo, InstMap0, DetInfo,
Goal - _, Msgs1),
Msgs = [ite_cond_cannot_succeed(GoalInfo) | Msgs1]
**********/
; Else0 = disj([], _) - _ ->
% (A -> C ; fail) is equivalent to (A, C)
goal_to_conj_list(Cond0, CondList),
goal_to_conj_list(Then0, ThenList),
list__append(CondList, ThenList, List),
simplify__goal(conj(List) - GoalInfo, Goal - _, Info0, Info)
;
simplify__goal(Cond0, Cond, Info0, Info1),
simplify_info_update_instmap(Info1, Cond, Info2),
simplify__goal(Then0, Then, Info2, Info3),
simplify_info_post_branch_update(Info0, Info3, Info4),
simplify__goal(Else0, Else, Info4, Info5),
simplify_info_post_branch_update(Info0, Info5, Info6),
Cond = _ - CondInfo,
goal_info_get_instmap_delta(CondInfo, CondDelta),
Then = _ - ThenInfo,
goal_info_get_instmap_delta(ThenInfo, ThenDelta),
instmap_delta_apply_instmap_delta(CondDelta, ThenDelta,
CondThenDelta),
Else = _ - ElseInfo,
goal_info_get_instmap_delta(ElseInfo, ElseDelta),
simplify_info_create_branch_info(Info0, Info6,
[ElseDelta, CondThenDelta], Info),
Goal = if_then_else(Vars, Cond, Then, Else, SM)
).
simplify__goal_2(not(Goal0), GoalInfo, Goal, GoalInfo, Info0, Info) :-
% Can't use calls or unifications seen within a negation,
% since non-local variables may not be bound within the negation.
simplify_info_get_common_info(Info0, Common),
simplify__goal(Goal0, Goal1, Info0, Info1),
simplify_info_set_common_info(Info1, Common, Info2),
(
% replace `not true' with `fail'
Goal1 = conj([]) - _GoalInfo
->
map__init(Empty),
Goal = disj([], Empty),
simplify_info_add_msg(Info2,
negated_goal_cannot_fail(GoalInfo), Info)
;
% replace `not fail' with `true'
Goal1 = disj([], _) - _GoalInfo2
->
Goal = conj([]),
simplify_info_add_msg(Info1,
negated_goal_cannot_succeed(GoalInfo), Info)
;
Goal = not(Goal1),
Info = Info2
).
simplify__goal_2(some(Vars1, Goal1), SomeInfo, Goal, SomeInfo, Info0, Info) :-
simplify__goal(Goal1, Goal2, Info0, Info),
simplify__nested_somes(Vars1, Goal2, Vars, Goal3),
Goal = some(Vars, Goal3).
simplify__goal_2(Goal0, GoalInfo, Goal, GoalInfo, Info0, Info) :-
Goal0 = pragma_c_code(_, _, PredId, ProcId, Args, _, _),
( simplify_do_calls(Info0) ->
common__optimise_call(PredId, ProcId, Args, Goal0,
GoalInfo, Goal, Info0, Info)
;
Info = Info0,
Goal = Goal0
).
%-----------------------------------------------------------------------------%
% simplify__input_args_are_equiv(Args, HeadVars, Modes,
% CommonInfo, ModuleInfo1):
% Succeeds if all the input arguments (determined by looking at
% `Modes') in `Args' are equivalent (according to the equivalence
% class specified by `CommonInfo') to the corresponding variables
% in HeadVars. HeadVars, Modes, and Args should all be lists of
% the same length.
:- pred simplify__input_args_are_equiv(list(var), list(var), list(mode),
common_info, module_info).
:- mode simplify__input_args_are_equiv(in, in, in, in, in) is semidet.
simplify__input_args_are_equiv([], [], _, _, _).
simplify__input_args_are_equiv([Arg|Args], [HeadVar|HeadVars], [Mode|Modes],
CommonInfo, ModuleInfo1) :-
( mode_is_input(ModuleInfo1, Mode) ->
common__vars_are_equivalent(Arg, HeadVar, CommonInfo)
;
true
),
simplify__input_args_are_equiv(Args, HeadVars, Modes,
CommonInfo, ModuleInfo1).
%-----------------------------------------------------------------------------%
% replace nested `some's with a single `some',
:- pred simplify__nested_somes(list(var)::in, hlds__goal::in,
list(var)::out, hlds__goal::out) is det.
simplify__nested_somes(Vars0, Goal0, Vars, Goal) :-
( Goal0 = some(Vars1, Goal1) - _ ->
list__append(Vars0, Vars1, Vars2),
simplify__nested_somes(Vars2, Goal1, Vars, Goal)
;
Vars = Vars0,
Goal = Goal0
).
%-----------------------------------------------------------------------------%
:- pred simplify__conj(list(hlds__goal), list(hlds__goal),
list(hlds__goal), hlds__goal_info,
simplify_info, simplify_info).
:- mode simplify__conj(in, in, out, in, in, out) is det.
simplify__conj([], RevGoals, Goals, _, Info, Info) :-
list__reverse(RevGoals, Goals).
simplify__conj([Goal0 | Goals0], RevGoals0, Goals, ConjInfo, Info0, Info) :-
% Flatten conjunctions.
( Goal0 = conj(SubGoals) - _ ->
list__append(SubGoals, Goals0, Goals1),
simplify__conj(Goals1, RevGoals0, Goals, ConjInfo, Info0, Info)
;
simplify_info_reset_branch_info(Info0, Info1, BranchInstMaps),
simplify__goal(Goal0, Goal1, Info1, Info2),
(
% Flatten conjunctions.
Goal1 = conj(SubGoals1) - _
->
simplify_info_undo_goal_updates(Info1, Info2, Info3),
simplify_info_set_branch_info(Info3, BranchInstMaps, Info4),
list__append(SubGoals1, Goals0, Goals1),
simplify__conj(Goals1, RevGoals0, Goals, ConjInfo, Info4, Info)
;
% Merge branching goals where the branches of the first goal
% contain extra information about the switched on variable
% of the second goal.
simplify__merge_adjacent_switches(Goal1, Goal, RevGoals0,
RevGoals1, BranchInstMaps, Info2, Info3)
->
simplify__conj([Goal | Goals0], RevGoals1, Goals,
ConjInfo, Info3, Info)
;
% Delete unreachable goals.
simplify_info_get_instmap(Info2, InstMap1),
instmap__is_unreachable(InstMap1)
->
Info = Info2,
simplify__conjoin_goal_and_rev_goal_list(Goal1,
RevGoals0, RevGoals),
list__reverse(RevGoals, Goals)
;
Goal1 = GoalExpr - _,
( goal_util__goal_is_branched(GoalExpr) ->
Info4 = Info2,
GoalNeeded = yes,
Goals1 = Goals0,
RevGoals1 = RevGoals0
;
simplify_info_set_branch_info(Info2, BranchInstMaps,
Info3),
simplify__excess_assigns(Goal1, ConjInfo,
Goals0, Goals1, RevGoals0, RevGoals1,
GoalNeeded, Info3, Info4)
),
( GoalNeeded = yes ->
simplify__conjoin_goal_and_rev_goal_list(Goal1,
RevGoals1, RevGoals2)
;
RevGoals2 = RevGoals1
),
simplify_info_update_instmap(Info4, Goal1, Info5),
simplify__conj(Goals1, RevGoals2, Goals,
ConjInfo, Info5, Info)
)
).
:- pred simplify__conjoin_goal_and_rev_goal_list(hlds__goal::in,
hlds__goals::in, hlds__goals::out) is det.
simplify__conjoin_goal_and_rev_goal_list(Goal, RevGoals0, RevGoals) :-
( Goal = conj(Goals) - _ ->
list__reverse(Goals, Goals1),
list__append(Goals1, RevGoals0, RevGoals)
;
RevGoals = [Goal | RevGoals0]
).
%-----------------------------------------------------------------------------%
% Check the post-branch instmaps from the last branching structure in
% the conjunction to see if there was more information about the
% switched on variable at the end of each branch than there is at the
% start of the current switch. If there is, it may be worth merging the
% goals.
:- pred simplify__merge_adjacent_switches(hlds__goal::in, hlds__goal::out,
hlds__goals::in, hlds__goals::out, maybe(branch_info)::in,
simplify_info::in, simplify_info::out) is semidet.
simplify__merge_adjacent_switches(SwitchGoal, Goal, RevGoals0, RevGoals,
MaybeBranchInfo, Info0, Info) :-
MaybeBranchInfo = yes(branch_info(RevInstMapDeltas,
PreGoalCommon, PreGoalInstMap)),
simplify_do_switch(Info0),
list__reverse(RevInstMapDeltas, BranchInstMaps),
BranchInstMaps \= [],
BranchInstMaps \= [_],
SwitchGoal = switch(Var, _, Cases2, SM) - _,
move_follow_code_select(RevGoals0, RevFollowGoals, RevGoals1),
RevGoals1 = [BranchedGoal | RevGoals],
BranchedGoal = BranchedGoalExpr - BranchedGoalInfo,
goal_util__goal_is_branched(BranchedGoalExpr),
simplify_info_get_instmap(Info0, InstMap),
simplify__check_branches_for_extra_info(Var, InstMap,
BranchInstMaps, Cases2, [], RevCaseList),
list__reverse(RevCaseList, CaseList),
list__reverse(RevFollowGoals, FollowGoals),
(
BranchedGoalExpr = switch(Var1, CanFail1, Cases1, _)
->
simplify__merge_switch_into_cases(Cases1,
FollowGoals, CaseList, Cases),
GoalExpr = switch(Var1, CanFail1, Cases, SM)
;
BranchedGoalExpr = if_then_else(Vars, Cond,
Then0, Else0, IteSM)
->
CaseList = [ThenCase, ElseCase],
simplify__merge_switch_into_goal(Then0, FollowGoals,
ThenCase, Then),
simplify__merge_switch_into_goal(Else0, FollowGoals,
ElseCase, Else),
GoalExpr = if_then_else(Vars, Cond, Then, Else, IteSM)
;
BranchedGoalExpr = disj(Disjuncts0, DisjSM)
->
simplify__merge_switch_into_goals(Disjuncts0,
FollowGoals, CaseList, Disjuncts),
GoalExpr = disj(Disjuncts, DisjSM)
;
error("simplify__merge_adjacent_switches")
),
list__append(FollowGoals, [SwitchGoal], NewGoals),
simplify__approximate_goal_info(NewGoals, BranchedGoalInfo, GoalInfo),
Goal = GoalExpr - GoalInfo,
simplify_info_set_requantify(Info0, Info1),
simplify_info_set_common_info(Info1, PreGoalCommon, Info2),
simplify_info_set_instmap(Info2, PreGoalInstMap, Info3),
simplify_info_reset_branch_info(Info3, Info, _).
% This just checks if every case in the second switch either fails
% or matches only one case given the information in the branches of
% the first branching goal. Returns the goal for the case that
% applies for each branch's instmap delta.
:- pred simplify__check_branches_for_extra_info(var::in,
instmap::in, list(instmap_delta)::in, list(case)::in,
list(hlds__goal)::in, list(hlds__goal)::out) is semidet.
simplify__check_branches_for_extra_info(_, _, [], _, CaseList, CaseList).
simplify__check_branches_for_extra_info(Var, InstMap,
[BranchInstMap | BranchInstMaps], Cases, CaseList0, CaseList) :-
instmap__lookup_var(InstMap, Var, InstMapInst),
instmap_delta_lookup_var(BranchInstMap, Var, BranchInstMapInst),
simplify__inst_contains_more_information(BranchInstMapInst,
InstMapInst, Cases, ThisCase),
simplify__check_branches_for_extra_info(Var, InstMap,
BranchInstMaps, Cases, [ThisCase | CaseList0], CaseList).
:- pred simplify__inst_contains_more_information((inst)::in,
(inst)::in, list(case)::in, hlds__goal::out) is semidet.
simplify__inst_contains_more_information(not_reached, _, _, Goal) :-
goal_info_init(GoalInfo),
map__init(SM),
Goal = disj([], SM) - GoalInfo.
simplify__inst_contains_more_information(bound(_, BoundInsts),
_, Cases0, Goal) :-
functors_to_cons_ids(BoundInsts, ConsIds0),
list__sort(ConsIds0, ConsIds),
delete_unreachable_cases(Cases0, ConsIds, Cases),
(
Cases = [],
goal_info_init(GoalInfo),
map__init(SM),
Goal = disj([], SM) - GoalInfo
;
Cases = [case(_, Goal)]
).
:- pred simplify__merge_switch_into_goals(hlds__goals::in, hlds__goals::in,
list(hlds__goal)::in, hlds__goals::out) is det.
simplify__merge_switch_into_goals([], _, [], []).
simplify__merge_switch_into_goals([], _, [_|_], []) :-
error("simplify__merge_switch_into_goals").
simplify__merge_switch_into_goals([_|_], _, [], []) :-
error("simplify__merge_switch_into_goals").
simplify__merge_switch_into_goals([Goal0 | Goals0], Builtins,
[SwitchGoal | SwitchGoals], [Goal | Goals]) :-
simplify__merge_switch_into_goal(Goal0, Builtins, SwitchGoal, Goal),
simplify__merge_switch_into_goals(Goals0, Builtins, SwitchGoals, Goals).
:- pred simplify__merge_switch_into_cases(list(case)::in, hlds__goals::in,
list(hlds__goal)::in, list(case)::out) is det.
simplify__merge_switch_into_cases([], _, [], []).
simplify__merge_switch_into_cases([], _, [_|_], []) :-
error("simplify__merge_switch_into_cases").
simplify__merge_switch_into_cases([_|_], _, [], []) :-
error("simplify__merge_switch_into_cases").
simplify__merge_switch_into_cases([case(ConsId, Goal0) | Cases0], Builtins,
[SwitchGoal | SwitchGoals], [case(ConsId, Goal) | Cases]) :-
simplify__merge_switch_into_goal(Goal0, Builtins, SwitchGoal, Goal),
simplify__merge_switch_into_cases(Cases0, Builtins, SwitchGoals, Cases).
:- pred simplify__merge_switch_into_goal(hlds__goal::in, hlds__goals::in,
hlds__goal::in, hlds__goal::out) is det.
simplify__merge_switch_into_goal(Goal0, Builtins, SwitchGoal, Goal) :-
conjoin_goal_and_goal_list(Goal0, Builtins, Goal1),
conjoin_goals(Goal1, SwitchGoal, Goal2),
Goal2 = GoalExpr - GoalInfo0,
( GoalExpr = conj(Goals) ->
simplify__approximate_goal_info(Goals, GoalInfo0, GoalInfo)
;
GoalInfo = GoalInfo0
),
Goal = GoalExpr - GoalInfo.
% Create a conservative goal_info so that simplification can
% safely be re-run on the resulting goal. A full recomputation over
% the entire goal is done later.
:- pred simplify__approximate_goal_info(list(hlds__goal)::in,
hlds__goal_info::in, hlds__goal_info::out) is det.
simplify__approximate_goal_info(NewGoals, GoalInfo0, GoalInfo) :-
ComputeGoalInfo =
lambda([Goal::in, GInfo0::in, GInfo::out] is det, (
Goal = _ - GInfo1,
goal_info_get_nonlocals(GInfo0, NonLocals0),
goal_info_get_instmap_delta(GInfo0, InstMapDelta0),
goal_info_get_instmap_delta(GInfo1, InstMapDelta1),
instmap_delta_apply_instmap_delta(InstMapDelta0,
InstMapDelta1, InstMapDelta),
goal_info_get_nonlocals(GInfo1, NonLocals1),
set__union(NonLocals0, NonLocals1, NonLocals),
goal_info_set_instmap_delta(GInfo0, InstMapDelta, GInfo2),
goal_info_set_nonlocals(GInfo2, NonLocals, GInfo3),
goal_info_get_determinism(GInfo3, Detism0),
goal_info_get_determinism(GInfo1, Detism1),
determinism_components(Detism0, CanFail0, MaxSolns0),
determinism_components(Detism1, CanFail1, MaxSolns1),
det_conjunction_maxsoln(MaxSolns0, MaxSolns1, MaxSolns),
det_conjunction_canfail(CanFail0, CanFail1, CanFail),
determinism_components(Detism, CanFail, MaxSolns),
goal_info_set_determinism(GInfo3, Detism, GInfo)
)),
list__foldl(ComputeGoalInfo, NewGoals, GoalInfo0, GoalInfo).
%-----------------------------------------------------------------------------%
:- pred simplify__excess_assigns(hlds__goal::in, hlds__goal_info::in,
hlds__goals::in, hlds__goals::out,
hlds__goals::in, hlds__goals::out, bool::out,
simplify_info::in, simplify_info::out) is det.
simplify__excess_assigns(Goal0, ConjInfo, Goals0, Goals,
RevGoals0, RevGoals, GoalNeeded, Info0, Info) :-
(
simplify_do_excess_assigns(Info0),
Goal0 = unify(_, _, _, Unif, _) - _,
goal_info_get_nonlocals(ConjInfo, NonLocals),
Unif = assign(LeftVar, RightVar),
( \+ set__member(LeftVar, NonLocals) ->
LocalVar = LeftVar, ReplacementVar = RightVar
; \+ set__member(RightVar, NonLocals) ->
LocalVar = RightVar, ReplacementVar = LeftVar
;
fail
)
->
GoalNeeded = no,
map__init(Subn0),
map__set(Subn0, LocalVar, ReplacementVar, Subn),
goal_util__rename_vars_in_goals(Goals0, no,
Subn, Goals),
goal_util__rename_vars_in_goals(RevGoals0, no,
Subn, RevGoals),
simplify_info_reset_branch_info(Info0, Info1, BranchInfo0),
(
BranchInfo0 = yes(
branch_info(InstMapDeltas0,
Common, PreBranchInstMap0))
->
simplify_info_get_instmap(Info1, InstMap0),
instmap__apply_sub(PreBranchInstMap0, no,
Subn, PreBranchInstMap),
instmap__apply_sub(InstMap0, no, Subn, InstMap),
Lambda = lambda([Delta0::in, Delta::out] is det, (
instmap_delta_apply_sub(Delta0, no, Subn, Delta)
)),
list__map(Lambda, InstMapDeltas0, InstMapDeltas),
simplify_info_set_instmap(Info1, InstMap, Info2),
simplify_info_set_branch_info(Info2,
yes(branch_info(InstMapDeltas,
Common, PreBranchInstMap)), Info3)
;
Info3 = Info1
),
simplify_info_get_varset(Info3, VarSet0),
varset__delete_var(VarSet0, LocalVar, VarSet),
simplify_info_set_varset(Info3, VarSet, Info)
;
GoalNeeded = yes,
Goals = Goals0,
RevGoals = RevGoals0,
Info = Info0
).
%-----------------------------------------------------------------------------%
:- pred simplify__switch(var, list(case), list(case), list(instmap_delta),
list(instmap_delta), simplify_info, simplify_info, simplify_info).
:- mode simplify__switch(in, in, out, in, out, in, in, out) is det.
simplify__switch(_, [], [], InstMaps, InstMaps, _, Info, Info).
simplify__switch(Var, [Case0 | Cases0], [Case | Cases],
InstMaps0, InstMaps, Info0, Info1, Info) :-
simplify_info_get_instmap(Info0, InstMap0),
Case0 = case(ConsId, Goal0),
simplify_info_get_module_info(Info1, ModuleInfo0),
instmap__bind_var_to_functor(Var, ConsId,
InstMap0, InstMap1, ModuleInfo0, ModuleInfo),
simplify_info_set_module_info(Info1, ModuleInfo, Info2),
simplify_info_set_instmap(Info2, InstMap1, Info3),
simplify__goal(Goal0, Goal, Info3, Info4),
simplify_info_post_branch_update(Info0, Info4, Info5),
Case = case(ConsId, Goal),
Goal0 = _ - GoalInfo,
goal_info_get_instmap_delta(GoalInfo, InstMapDelta),
simplify__switch(Var, Cases0, Cases, [InstMapDelta | InstMaps0],
InstMaps, Info0, Info5, Info).
% Create a semidet unification at the start of a singleton case
% in a can_fail switch.
:- pred simplify__create_test_unification(var::in, cons_id::in, int::in,
hlds__goal::out, simplify_info::in, simplify_info::out) is det.
simplify__create_test_unification(Var, ConsId, ConsArity,
ExtraGoal - ExtraGoalInfo, Info0, Info) :-
simplify_info_get_varset(Info0, VarSet0),
simplify_info_get_var_types(Info0, VarTypes0),
varset__new_vars(VarSet0, ConsArity, ArgVars, VarSet),
map__lookup(VarTypes0, Var, VarType),
simplify_info_get_module_info(Info0, ModuleInfo),
type_util__get_cons_id_arg_types(ModuleInfo,
VarType, ConsId, ArgTypes),
map__det_insert_from_corresponding_lists(VarTypes0, ArgVars,
ArgTypes, VarTypes),
simplify_info_set_varset(Info0, VarSet, Info1),
simplify_info_set_var_types(Info1, VarTypes, Info),
simplify_info_get_instmap(Info, InstMap),
instmap__lookup_var(InstMap, Var, Inst0),
(
inst_expand(ModuleInfo, Inst0, Inst1),
get_arg_insts(Inst1, ConsId, ConsArity, ArgInsts1)
->
ArgInsts = ArgInsts1
;
error("simplify__goal_2 - get_arg_insts failed")
),
InstToUniMode =
lambda([ArgInst::in, ArgUniMode::out] is det, (
ArgUniMode = ((ArgInst - ArgInst) -> (free - ArgInst))
)),
list__map(InstToUniMode, ArgInsts, UniModes),
UniMode = (Inst0 -> Inst0) - (Inst0 -> Inst0),
UnifyContext = unify_context(explicit, []),
Unification = deconstruct(Var, ConsId,
ArgVars, UniModes, can_fail),
ExtraGoal = unify(Var, functor(ConsId, ArgVars),
UniMode, Unification, UnifyContext),
goal_info_init(ExtraGoalInfo0),
set__singleton_set(NonLocals, Var),
goal_info_set_nonlocals(ExtraGoalInfo0, NonLocals, ExtraGoalInfo1),
goal_info_set_determinism(ExtraGoalInfo1, semidet, ExtraGoalInfo).
%-----------------------------------------------------------------------------%
:- pred simplify__disj(list(hlds__goal), list(hlds__goal), list(instmap_delta),
list(instmap_delta), simplify_info, simplify_info, simplify_info).
:- mode simplify__disj(in, out, in, out, in, in, out) is det.
simplify__disj([], [], InstMaps, InstMaps, _, Info, Info).
simplify__disj([Goal0 |Goals0], [Goal | Goals], PostBranchInstMaps0,
PostBranchInstMaps, Info0, Info1, Info) :-
simplify__goal(Goal0, Goal, Info1, Info2),
simplify_info_post_branch_update(Info0, Info2, Info3),
Goal0 = _ - GoalInfo,
goal_info_get_instmap_delta(GoalInfo, InstMapDelta),
simplify__disj(Goals0, Goals, [InstMapDelta | PostBranchInstMaps0],
PostBranchInstMaps, Info0, Info3, Info4),
(
simplify_do_warn(Info4),
Goal = _ - GoalInfo,
goal_info_get_determinism(GoalInfo, Detism),
determinism_components(Detism, _, MaxSolns),
MaxSolns = at_most_zero
->
simplify_info_add_msg(Info4, zero_soln_disjunct(GoalInfo),
Info)
;
Info = Info4
).
% Disjunctions that cannot succeed more than once when viewed from the
% outside generally need some fixing up, and/or some warnings to be
% issued.
% Currently we just convert them all to if-then-elses.
% XXX converting disjs that have output variables but that
% nevertheless cannot succeed more than one
% (e.g. cc_nondet or cc_multi disjs) into if-then-elses
% may cause problems with other parts of the compiler that
% assume that an if-then-else is mode-correct, i.e. that
% the condition doesn't bind variables.
:- pred simplify__fixup_disj(list(hlds__goal), determinism, bool,
hlds__goal_info, follow_vars, hlds__goal_expr,
simplify_info, simplify_info).
:- mode simplify__fixup_disj(in, in, in, in, in, out, in, out) is det.
simplify__fixup_disj(Disjuncts, _, _OutputVars, GoalInfo, SM,
Goal, Info0, Info) :-
det_disj_to_ite(Disjuncts, GoalInfo, SM, IfThenElse),
simplify__goal(IfThenElse, Simplified, Info0, Info),
Simplified = Goal - _.
% det_disj_to_ite is used to transform disjunctions that occur
% in prunable contexts into if-then-elses.
% For example, it would transform
%
% ( Disjunct1
% ; Disjunct2
% ; Disjunct3
% )
% into
% ( Disjunct1 ->
% true
% ; Disjunct2 ->
% true
% ;
% Disjunct3
% ).
:- pred det_disj_to_ite(list(hlds__goal), hlds__goal_info, follow_vars,
hlds__goal).
:- mode det_disj_to_ite(in, in, in, out) is det.
det_disj_to_ite([], _GoalInfo, _SM, _) :-
error("reached base case of det_disj_to_ite").
det_disj_to_ite([Disjunct | Disjuncts], GoalInfo, SM, Goal) :-
( Disjuncts = [] ->
Goal = Disjunct
;
Cond = Disjunct,
Cond = _CondGoal - CondGoalInfo,
goal_info_init(ThenGoalInfo0),
instmap_delta_init_reachable(InstMap1),
goal_info_set_instmap_delta(ThenGoalInfo0, InstMap1,
ThenGoalInfo1),
goal_info_set_determinism(ThenGoalInfo1, det, ThenGoalInfo),
Then = conj([]) - ThenGoalInfo,
det_disj_to_ite(Disjuncts, GoalInfo, SM, Rest),
Rest = _RestGoal - RestGoalInfo,
goal_info_get_nonlocals(CondGoalInfo, CondNonLocals),
goal_info_get_nonlocals(RestGoalInfo, RestNonLocals),
set__union(CondNonLocals, RestNonLocals, NonLocals),
goal_info_set_nonlocals(GoalInfo, NonLocals, NewGoalInfo0),
goal_info_get_instmap_delta(GoalInfo, InstMapDelta0),
instmap_delta_restrict(InstMapDelta0, NonLocals, InstMapDelta),
goal_info_set_instmap_delta(NewGoalInfo0, InstMapDelta,
NewGoalInfo1),
goal_info_get_determinism(CondGoalInfo, CondDetism),
goal_info_get_determinism(RestGoalInfo, RestDetism),
determinism_components(CondDetism, CondCanFail, CondMaxSoln),
determinism_components(RestDetism, RestCanFail, RestMaxSoln),
det_disjunction_canfail(CondCanFail, RestCanFail, CanFail),
det_disjunction_maxsoln(CondMaxSoln, RestMaxSoln, MaxSoln0),
( MaxSoln0 = at_most_many ->
MaxSoln = at_most_one
;
MaxSoln = MaxSoln0
),
determinism_components(Detism, CanFail, MaxSoln),
goal_info_set_determinism(NewGoalInfo1, Detism, NewGoalInfo),
Goal = if_then_else([], Cond, Then, Rest, SM) - NewGoalInfo
).
%-----------------------------------------------------------------------------%
:- pred simplify__contains_multisoln_goal(list(hlds__goal)::in) is semidet.
simplify__contains_multisoln_goal(Goals) :-
list__member(_Goal - GoalInfo, Goals),
goal_info_get_determinism(GoalInfo, Detism),
determinism_components(Detism, _, at_most_many).
%-----------------------------------------------------------------------------%
:- type simplify_info
---> simplify_info(
det_info,
set(det_msg),
simplify, % How much simplification to do.
common_info, % Info about common subexpressions.
instmap,
varset,
map(var, type),
bool, % Does the goal need requantification.
bool, % Does mode analysis need rerunning
% rather than recompute_instmap_delta.
maybe(branch_info) % Final instmaps at the end
% of each branch of the last
% branching goal
).
% info used to merge adjacent switches and prepare for rerunning
% simplification on the resulting goal.
:- type branch_info
---> branch_info(
list(instmap_delta), % instmap_delta for each branch
common_info, % from before goal
instmap % from before goal
).
simplify_info_init(DetInfo, Simplify, InstMap, VarSet, VarTypes, Info) :-
set__init(Msgs),
common_info_init(CommonInfo),
Info = simplify_info(DetInfo, Msgs, Simplify, CommonInfo,
InstMap, VarSet, VarTypes, no, no, no).
% exported for common.m
:- interface.
:- pred simplify_info_get_det_info(simplify_info::in, det_info::out) is det.
:- pred simplify_info_get_msgs(simplify_info::in, set(det_msg)::out) is det.
:- pred simplify_info_get_instmap(simplify_info::in, instmap::out) is det.
:- pred simplify_info_get_simplify(simplify_info::in, simplify::out) is det.
:- pred simplify_info_get_common_info(simplify_info::in,
common_info::out) is det.
:- pred simplify_info_get_varset(simplify_info::in, varset::out) is det.
:- pred simplify_info_get_var_types(simplify_info::in,
map(var, type)::out) is det.
:- pred simplify_info_requantify(simplify_info::in) is semidet.
:- pred simplify_info_recompute_atomic(simplify_info::in) is semidet.
:- pred simplify_info_get_branch_info(simplify_info::in,
maybe(branch_info)::out) is det.
:- pred simplify_info_get_module_info(simplify_info::in,
module_info::out) is det.
:- implementation.
simplify_info_get_det_info(simplify_info(Det, _,_,_,_,_,_,_,_,_), Det).
simplify_info_get_msgs(simplify_info(_, Msgs, _,_,_,_,_,_,_,_), Msgs).
simplify_info_get_simplify(simplify_info(_,_,Simplify,_,_,_,_,_,_,_),
Simplify).
simplify_info_get_common_info(simplify_info(_,_,_,Common, _,_,_,_,_,_),
Common).
simplify_info_get_instmap(simplify_info(_,_,_,_, InstMap,_,_,_,_,_), InstMap).
simplify_info_get_varset(simplify_info(_,_,_,_,_, VarSet, _,_,_,_), VarSet).
simplify_info_get_var_types(simplify_info(_,_,_,_,_,_, VarTypes, _,_,_),
VarTypes).
simplify_info_requantify(simplify_info(_,_,_,_,_,_,_, yes, _,_)).
simplify_info_recompute_atomic(simplify_info(_,_,_,_,_,_,_,_, yes,_)).
simplify_info_get_branch_info(simplify_info(_,_,_,_,_,_,_,_,_, BranchInfo),
BranchInfo).
simplify_info_get_module_info(Info, ModuleInfo) :-
simplify_info_get_det_info(Info, DetInfo),
det_info_get_module_info(DetInfo, ModuleInfo).
:- interface.
:- type branch_info.
:- pred simplify_info_set_det_info(simplify_info::in,
det_info::in, simplify_info::out) is det.
:- pred simplify_info_set_msgs(simplify_info::in,
set(det_msg)::in, simplify_info::out) is det.
:- pred simplify_info_set_simplify(simplify_info::in,
simplify::in, simplify_info::out) is det.
:- pred simplify_info_set_instmap(simplify_info::in,
instmap::in, simplify_info::out) is det.
:- pred simplify_info_set_common_info(simplify_info::in, common_info::in,
simplify_info::out) is det.
:- pred simplify_info_set_varset(simplify_info::in, varset::in,
simplify_info::out) is det.
:- pred simplify_info_set_var_types(simplify_info::in, map(var, type)::in,
simplify_info::out) is det.
:- pred simplify_info_set_requantify(simplify_info::in,
simplify_info::out) is det.
:- pred simplify_info_set_recompute_atomic(simplify_info::in,
simplify_info::out) is det.
:- pred simplify_info_reset_branch_info(simplify_info::in, simplify_info::out,
maybe(branch_info)::out) is det.
:- pred simplify_info_set_branch_info(simplify_info::in,
maybe(branch_info)::in, simplify_info::out) is det.
:- pred simplify_info_add_msg(simplify_info::in, det_msg::in,
simplify_info::out) is det.
:- pred simplify_info_set_module_info(simplify_info::in,
module_info::in, simplify_info::out) is det.
:- implementation.
simplify_info_set_det_info(simplify_info(_, B, C, D, E, F, G, H, I,J), Det,
simplify_info(Det, B, C, D, E, F, G, H, I,J)).
simplify_info_set_msgs(simplify_info(A, _, C, D, E, F, G, H, I,J), Msgs,
simplify_info(A, Msgs, C, D, E, F, G, H, I, J)).
simplify_info_set_simplify(simplify_info(A, B, _, D, E, F, G, H, I,J), Simp,
simplify_info(A, B, Simp, D, E, F, G, H, I,J)).
simplify_info_set_instmap(simplify_info(A, B, C, D, _, F, G, H, I, J), InstMap,
simplify_info(A, B, C, D, InstMap, F, G, H, I, J)).
simplify_info_set_common_info(simplify_info(A, B, C, _, E, F, G, H, I, J),
Common, simplify_info(A, B, C, Common, E, F, G, H, I, J)).
simplify_info_set_varset(simplify_info(A, B, C, D, E, _, G, H, I, J), VarSet,
simplify_info(A, B, C, D, E, VarSet, G, H, I, J)).
simplify_info_set_var_types(simplify_info(A, B, C, D, E, F, _, H, I, J),
VarTypes, simplify_info(A, B, C, D, E, F, VarTypes, H, I, J)).
simplify_info_set_requantify(simplify_info(A, B, C, D, E, F, G, _, I, J),
simplify_info(A, B, C, D, E, F, G, yes, I, J)).
simplify_info_set_recompute_atomic(simplify_info(A, B, C, D, E, F, G, H, _, J),
simplify_info(A, B, C, D, E, F, G, H, yes, J)).
simplify_info_reset_branch_info(simplify_info(A, B, C, D, E, F, G, H, I, Info),
simplify_info(A, B, C, D, E, F, G, H, I, no), Info).
simplify_info_set_branch_info(simplify_info(A, B, C, D, E, F, G, H, I, _),
Info, simplify_info(A, B, C, D, E, F, G, H, I, Info)).
simplify_info_add_msg(Info0, Msg, Info) :-
( simplify_do_warn(Info0) ->
simplify_info_get_msgs(Info0, Msgs0),
set__insert(Msgs0, Msg, Msgs),
simplify_info_set_msgs(Info0, Msgs, Info)
;
Info = Info0
).
simplify_info_set_module_info(Info0, ModuleInfo, Info) :-
simplify_info_get_det_info(Info0, DetInfo0),
det_info_set_module_info(DetInfo0, ModuleInfo, DetInfo),
simplify_info_set_det_info(Info0, DetInfo, Info).
:- interface.
:- pred simplify_do_warn(simplify_info::in) is semidet.
:- pred simplify_do_warn_calls(simplify_info::in) is semidet.
:- pred simplify_do_once(simplify_info::in) is semidet.
:- pred simplify_do_switch(simplify_info::in) is semidet.
:- pred simplify_do_common(simplify_info::in) is semidet.
:- pred simplify_do_excess_assigns(simplify_info::in) is semidet.
:- pred simplify_do_calls(simplify_info::in) is semidet.
:- implementation.
simplify_do_warn(Info) :-
simplify_info_get_simplify(Info, Simplify),
Simplify = simplify(yes, _, _, _, _, _, _).
simplify_do_warn_calls(Info) :-
simplify_info_get_simplify(Info, Simplify),
Simplify = simplify(_, yes, _, _, _, _, _).
simplify_do_once(Info) :-
simplify_info_get_simplify(Info, Simplify),
Simplify = simplify(_, _, yes, _, _, _, _).
simplify_do_switch(Info) :-
simplify_info_get_simplify(Info, Simplify),
Simplify = simplify(_, _, _, yes, _, _, _).
simplify_do_common(Info) :-
simplify_info_get_simplify(Info, Simplify),
Simplify = simplify(_, _, _, _, yes, _, _).
simplify_do_excess_assigns(Info) :-
simplify_info_get_simplify(Info, Simplify),
Simplify = simplify(_, _, _, _, _, yes, _).
simplify_do_calls(Info) :-
simplify_info_get_simplify(Info, Simplify),
Simplify = simplify(_, _, _, _, _, _, yes).
:- pred simplify_info_update_instmap(simplify_info::in, hlds__goal::in,
simplify_info::out) is det.
simplify_info_update_instmap(
simplify_info(A, B, C, D, InstMap0, F, G, H, I, J), Goal,
simplify_info(A, B, C, D, InstMap, F, G, H, I, J)) :-
update_instmap(Goal, InstMap0, InstMap).
:- type before_after
---> before
; after.
% Clear the common_info structs accumulated since the last goal that
% could cause a stack flush. This is done to avoid replacing a
% deconstruction with assignments to the arguments where this
% would cause more variables to be live across the stack flush.
% Calls and construction unifications are not treated in this
% way since it is nearly always better to optimize them away.
:- pred simplify_info_maybe_clear_structs(before_after::in, hlds__goal::in,
simplify_info::in, simplify_info::out) is det.
simplify_info_maybe_clear_structs(BeforeAfter, Goal, Info0, Info) :-
( code_util__cannot_stack_flush(Goal) ->
Info = Info0
;
% First check to see if a call is common and can be replaced
% by a series of unifications.
simplify_do_common(Info0),
(
BeforeAfter = after
;
BeforeAfter = before,
Goal = GoalExpr - _,
GoalExpr \= call(_, _, _, _, _, _),
GoalExpr \= higher_order_call(_, _, _, _, _),
GoalExpr \= pragma_c_code(_, _, _, _, _, _, _)
)
->
simplify_info_get_common_info(Info0, CommonInfo0),
common_info_clear_structs(CommonInfo0, CommonInfo),
simplify_info_set_common_info(Info0, CommonInfo, Info)
;
Info = Info0
).
% Reset the instmap and seen calls for the next branch.
:- pred simplify_info_post_branch_update(simplify_info::in, simplify_info::in,
simplify_info::out) is det.
simplify_info_post_branch_update(PreBranchInfo, PostBranchInfo0, Info) :-
simplify_info_get_instmap(PreBranchInfo, InstMap),
simplify_info_set_instmap(PostBranchInfo0, InstMap, PostBranchInfo1),
simplify_info_get_common_info(PreBranchInfo, Common),
simplify_info_set_common_info(PostBranchInfo1, Common, Info).
:- pred simplify_info_create_branch_info(simplify_info::in, simplify_info::in,
list(instmap_delta)::in, simplify_info::out) is det.
simplify_info_create_branch_info(Info0, Info1, InstMapDeltas, Info) :-
simplify_info_get_common_info(Info0, Common),
simplify_info_get_instmap(Info0, InstMap),
BranchInfo = yes(branch_info(InstMapDeltas, Common, InstMap)),
simplify_info_set_branch_info(Info1, BranchInfo, Info).
% Undo updates to the simplify_info before redoing
% simplification on a goal.
:- pred simplify_info_undo_goal_updates(simplify_info::in, simplify_info::in,
simplify_info::out) is det.
simplify_info_undo_goal_updates(Info1, Info2, Info) :-
simplify_info_get_common_info(Info1, CommonInfo0),
simplify_info_set_common_info(Info2, CommonInfo0, Info3),
simplify_info_get_branch_info(Info1, BranchInfo),
simplify_info_set_branch_info(Info3, BranchInfo, Info4),
simplify_info_get_instmap(Info1, InstMap),
simplify_info_set_instmap(Info4, InstMap, Info).