Files
mercury/compiler/unneeded_code.m
Zoltan Somogyi a2bf36e49a This diff contains no changes in algorithms whatsoever.
Estimated hours taken: 4
Branches: main

This diff contains no changes in algorithms whatsoever.

browser/*.m:
compiler/*.m:
library/*.m:
	Replace old-style lambdas with new-style lambdas or with named
	procedures.
2003-11-05 03:17:49 +00:00

1233 lines
47 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 2000-2003 The University of Melbourne.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%-----------------------------------------------------------------------------%
%
% Author: zs.
%
% This module implements two related source-to-source transforms,
% both of which focus on goals that produce some variables, where these
% variables are not always required by the following computation.
%
% If there are no computation paths on which the variables produced by a goal
% may be needed, then the first transform deletes that goal.
%
% If the variables produced by a goal may be needed on some but not all
% computation paths, then the second transform moves that goal to the starts
% of those computation paths, thus avoiding the cost of executing the goal
% on all other computation paths. (This is related to the concept of partial
% redundancy elimination (PRE) for imperative languages.)
%
% Mercury has two constructs that make it possible for a variable to be needed
% on some computation paths but not others: switches and if-then-elses.
%
% In the case of switches, the alternative computation paths are those
% corresponding to the possible values of the switched-on variable, and
% not just the switch arms. Even if all switch arms need a variable, it
% is an optimization to copy the code generating that variable to the starts of
% all the switch arms if the switch is can_fail, i.e. there are some function
% symbols that the switched-on variable can be bound to that do not have arms.
%
% In the case of if-then-elses, the alternatives are the then part and
% the else part. Any variable needed by the condition is needed in both those
% computation paths.
%
% From the point of view of this transform, disjunctions are not branched
% control structures, because entering a disjunct does not preclude later
% entering another disjunct. Any variable needed by any disjunct must therefore
% be produced before control enters the disjunction. (In theory, a disjunct
% that cannot fail in a model_semi disjunction prevents entry to the following
% disjuncts, but any such following disjuncts will have been removed long ago
% by simplification.)
%
% Note that by avoiding the execution of a goal that appears in the original
% source code of the program, both these transforms can in general change the
% operational semantics of the program. Therefore a goal can only be eliminated
% or moved if the goal is has no observable effect except the result it
% generates (i.e is pure, cannot fail, cannot loop, cannot raise an exception),
% which is usually true only of goals composed entirely of builtins, or if
% the semantics options explicitly permit the change in the operational
% semantics, which will usually be an improvement (e.g. avoiding an infinite
% loop or an unnecessary exception).
%
%-----------------------------------------------------------------------------%
:- module transform_hlds__unneeded_code.
:- interface.
:- import_module hlds__hlds_module.
:- import_module hlds__hlds_pred.
:- import_module io.
:- pred unneeded_code__process_proc_msg(pred_id::in, proc_id::in,
proc_info::in, proc_info::out, module_info::in, module_info::out,
io__state::di, io__state::uo) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module check_hlds__goal_path.
:- import_module check_hlds__inst_match.
:- import_module check_hlds__mode_util.
:- import_module hlds__goal_form.
:- import_module hlds__hlds_goal.
:- import_module hlds__hlds_out.
:- import_module hlds__instmap.
:- import_module hlds__passes_aux.
:- import_module hlds__quantification.
:- import_module libs__globals.
:- import_module libs__options.
:- import_module ll_backend__code_aux.
:- import_module parse_tree__prog_data.
:- import_module bool, int, list, assoc_list, map, set, std_util, require.
% The branch_alts and branch_point types record the information the
% transform needs to know about a particular branched control
% structure: where it is, what kind it is, and how many alternatives
% it has.
:- type branch_point
---> branch_point(
goal_path, % The position of the branch point.
branch_alts % What kind of goal the branch point
% is, and many branches it has.
% Note that the second argument is a
% function of the first.
).
:- type branch_alts
---> ite % If-then-elses always have two
% alternatives: the then branch
% (numbered 1) and the else branch
% (numbered 2).
; switch(int). % The number of alternatives in a
% switch is equal to the number of
% function symbols in the type of
% the switched-on variable; this number
% is given by the argument. If the
% switch cannot_fail, then this will be
% equal to the number of cases;
% if the switch can_fail, there will be
% strictly fewer cases than this.
% The location type identifies one arm of a branched control structure.
% The branched control structure id is a branch_point instead of a
% simple goal_path because without the branch_alts info, the
% transformation cannot tell if a given set of branches of a branched
% control structure covers all possible execution paths or not.
:- type location
---> location(
branch_point, % To which branched control structure
% does the location belong.
int % The branch within that control
% structure.
).
% The where_needed_map type maps each variable to the set of
% computation branches where it is needed. If a variable is needed
% everywhere, then the computation producing it cannot be eliminated
% or moved. If it is not needed at all, its producer can be eliminated.
% If it is needed on some but not all branches, then the producer
% can be moved to the starts of those branches.
%
% The set of branches to whose starts the producer can be moved
% is represented as a map from the id of the branched control
% structure to the set of branch numbers within that branched control
% structure. If the branched control structure at goal path gp is
% mapped to a set including N, then the producer of that variable
% may be moved to the start of the goal with goal path <gp>;sN;
% (if the control structure is a switch) or <gp>;t; or <gp>;e;
% (if the control structure is an if-then-else).
%
% Since <gp>;sN; is conjoined with e.g. <gp>;sN;<gp2>;sM;
% it would be a mode error (variable having two conjoined producers)
% for the transformed code to have the producer of some variable
% inserted at the start of both those goals. It is therefore an
% invariant that a where_needed structure mapping gp to N
% will not contain any keys whose goal_path includes <gp>;sN;
% or its if-then-else equivalent.
%
% An example:
%
% % switch on X at goal path gp
% ( % s1
% X = a,
% ... code that needs Y and Z ...
% ; % s2
% X = b,
% ( Y = f ->
% ... code that needs only Z ...
% ;
% ... code that does not need Y or Z ...
% )
% )
%
% X is needed everywhere, since even if X is bound to c, its value must
% be tested.
%
% Y is needed everywhere iff the type of X contains only a and b,
% otherwise it is needed only in the <gp>;s1; and <gp>;s2; switch arms.
%
% Z is needed in <gp>;s1; and <gp>;s2;t; but is not needed in the
% <gp>;s2;e; else arm. Therefore the where_needed_branches map for Z
% will map gp to 1 and <gp>;s2; to 1.
:- type where_needed_map == map(prog_var, where_needed).
:- type where_needed
---> everywhere
; branches(where_needed_branches).
:- type where_needed_branches == map(branch_point, set(int)).
% The refined_goal_map structure maps branch goals to the list of
% producers that should be moved to the start of that branch.
% The order is important, since some of the producers in such a list
% may depend on variables produced by other goals that precede them
% in the list.
:- type refined_goal_map == map(pair(goal_path, int), list(hlds_goal)).
%-----------------------------------------------------------------------------%
% The transformation considers every nonlocal variable of a goal
% that is bound on entry to be consumed by that goal. If the nonlocal set
% contains any such variables that are not actually needed by the goal,
% then the transformation will not be as effective as it could be.
% Therefore we preprocess the procedure body to ensure that the nonlocals
% sets are accurate reflections of the true needs of goals.
unneeded_code__process_proc_msg(PredId, ProcId, ProcInfo0, ProcInfo,
ModuleInfo0, ModuleInfo) -->
globals__io_lookup_bool_option(very_verbose, VeryVerbose),
( { VeryVerbose = yes } ->
io__write_string("% Removing dead code in "),
hlds_out__write_pred_proc_id(ModuleInfo0, PredId, ProcId),
io__write_string(": "),
{ unneeded_code__pre_process_proc(ProcInfo0, ProcInfo1) },
{ unneeded_code__process_proc(ProcInfo1, ProcInfo,
ModuleInfo0, ModuleInfo, Successful) },
(
{ Successful = yes },
io__write_string("done.\n")
;
{ Successful = no },
io__write_string("none found.\n")
)
;
{ unneeded_code__pre_process_proc(ProcInfo0, ProcInfo1) },
{ unneeded_code__process_proc(ProcInfo1, ProcInfo,
ModuleInfo0, ModuleInfo, _) }
).
:- pred unneeded_code__pre_process_proc(proc_info::in, proc_info::out) is det.
unneeded_code__pre_process_proc(!ProcInfo) :-
proc_info_headvars(!.ProcInfo, HeadVars),
proc_info_goal(!.ProcInfo, Goal0),
proc_info_varset(!.ProcInfo, Varset0),
proc_info_vartypes(!.ProcInfo, VarTypes0),
implicitly_quantify_clause_body(HeadVars, _Warnings, Goal0, Goal,
Varset0, Varset, VarTypes0, VarTypes),
proc_info_set_goal(Goal, !ProcInfo),
proc_info_set_varset(Varset, !ProcInfo),
proc_info_set_vartypes(VarTypes, !ProcInfo).
% The source-to-source transform operates in two phases.
%
% The first phase traverses the procedure body, keeping track of which
% variables are needed where. When it finds a goal that can be deleted,
% it deletes it by replacing it with the goal `true' (i.e. conj([])).
% When it finds a goal that can be moved, it does the same, but also
% records in the RefinedGoalsMap that the deleted goal must later be
% inserted at the starts of the branches where its outputs may be needed,
% and accordingly notes that its own inputs are needed in those branches.
%
% The second phase traverses the modified problem body, and inserts the
% goals in the RefinedGoalsMap at the starts of the indicated branches.
% This phase identified the indicated branches by the goal_path annotations
% on their parents. These may be out of date since the first phase will have
% deleted some goals, but since neither phase modifies the goal_path annotation
% on a goal once that goal has been inserted into the RefinedGoalsMap,
% this does not matter.
%
% Neither phase traverses the internals of a goal that has been moved.
% To make sure that such goals are optimized whenever possible, the algorithm
% invokes itself recursively whenever it was able to successfully (delete or)
% move a goal. This cannot lead to infinite recursion, since each iteration
% will strictly reduce the number of computation paths on which a subgoal
% of the procedure body is executed. Since both the number of subgoals and
% computation paths are finite, the recursion must end.
:- type option_values
---> option_values(
fully_strict :: bool,
reorder_conj :: bool,
copy_limit :: int
).
:- pred unneeded_code__process_proc(proc_info::in, proc_info::out,
module_info::in, module_info::out, bool::out) is det.
unneeded_code__process_proc(!ProcInfo, !ModuleInfo, Successful) :-
goal_path__fill_slots(!.ModuleInfo, !ProcInfo),
proc_info_goal(!.ProcInfo, Goal0),
proc_info_varset(!.ProcInfo, Varset0),
proc_info_vartypes(!.ProcInfo, VarTypes0),
proc_info_get_initial_instmap(!.ProcInfo, !.ModuleInfo, InstMap0),
Goal0 = _ - GoalInfo0,
goal_info_get_instmap_delta(GoalInfo0, InstMapDelta),
instmap__apply_instmap_delta(InstMap0, InstMapDelta, InstMap),
proc_info_instantiated_head_vars(!.ModuleInfo, !.ProcInfo,
NeededVarsList),
map__init(WhereNeededMap0),
NeededEverywhere =
(pred(Var::in, NeededMap0::in, NeededMap::out) is det :-
map__det_insert(NeededMap0, Var, everywhere, NeededMap)
),
list__foldl(NeededEverywhere, NeededVarsList,
WhereNeededMap0, WhereNeededMap1),
map__init(RefinedGoals0),
module_info_globals(!.ModuleInfo, Globals),
globals__lookup_bool_option(Globals, reorder_conj, ReorderConj),
globals__lookup_bool_option(Globals, fully_strict, FullyStrict),
globals__lookup_int_option(Globals, unneeded_code_copy_limit,
Limit),
Options = option_values(FullyStrict, ReorderConj, Limit),
unneeded_code__process_goal(Goal0, Goal1, InstMap0, InstMap,
VarTypes0, !.ModuleInfo, Options, WhereNeededMap1, _,
RefinedGoals0, RefinedGoals1, no, Changed),
unneeded_code__refine_goal(Goal1, RefinedGoals1, Goal2, RefinedGoals),
require(map__is_empty(RefinedGoals),
"unneeded_code__process_proc: goal reattachment unsuccessful"),
( Changed = yes ->
% We need to fix up the goal_info by recalculating
% the nonlocal vars and the non-atomic instmap deltas.
proc_info_headvars(!.ProcInfo, HeadVars),
proc_info_inst_varset(!.ProcInfo, InstVarSet),
implicitly_quantify_clause_body(HeadVars, _Warnings,
Goal2, Goal3, Varset0, Varset, VarTypes0, VarTypes),
recompute_instmap_delta(no, Goal3, Goal, VarTypes, InstVarSet,
InstMap0, !ModuleInfo),
proc_info_set_goal(Goal, !ProcInfo),
proc_info_set_varset(Varset, !ProcInfo),
proc_info_set_vartypes(VarTypes, !ProcInfo),
unneeded_code__process_proc(!ProcInfo, !ModuleInfo, _),
Successful = yes
;
Successful = no
).
:- pred unneeded_code__process_goal(hlds_goal::in, hlds_goal::out, instmap::in,
instmap::in, vartypes::in, module_info::in, option_values::in,
where_needed_map::in, where_needed_map::out,
refined_goal_map::in, refined_goal_map::out,
bool::in, bool::out) is det.
unneeded_code__process_goal(Goal0, Goal, InstMap0, InstMap, VarTypes,
ModuleInfo, Options, WhereNeededMap0, WhereNeededMap,
RefinedGoals0, RefinedGoals, Changed0, Changed) :-
unneeded_code__can_eliminate_or_move(Goal0, InstMap0, InstMap,
VarTypes, ModuleInfo, Options, WhereNeededMap0, WhereInfo),
(
WhereInfo = everywhere,
unneeded_code__process_goal_internal(Goal0, Goal,
InstMap0, InstMap, VarTypes, ModuleInfo, Options,
WhereNeededMap0, WhereNeededMap1,
RefinedGoals0, RefinedGoals, Changed0, Changed)
;
WhereInfo = branches(Branches),
unneeded_code__demand_inputs(Goal0, ModuleInfo, InstMap0,
WhereInfo, WhereNeededMap0, WhereNeededMap1),
map__to_assoc_list(Branches, BranchList),
list__foldl(unneeded_code__insert_branch_into_refined_goals(
Goal0), BranchList, RefinedGoals0, RefinedGoals),
true_goal(Goal),
Changed = yes
),
unneeded_code__undemand_virgin_outputs(Goal0, ModuleInfo, InstMap0,
WhereNeededMap1, WhereNeededMap2),
(
Goal = _ - GoalInfo,
goal_info_get_features(GoalInfo, Features),
set__member((impure), Features)
->
% By saying that all vars that are live before
% the impure goal are needed everywhere, we prevent
% the movement of the goals producing those vars
% across the impure goal.
%
% This code requires compound goals containing impure
% code to also be marked impure.
map__map_values(unneeded_code__demand_var_everywhere,
WhereNeededMap2, WhereNeededMap)
;
WhereNeededMap = WhereNeededMap2
).
:- pred unneeded_code__insert_branch_into_refined_goals(hlds_goal::in,
pair(branch_point, set(int))::in,
refined_goal_map::in, refined_goal_map::out) is det.
unneeded_code__insert_branch_into_refined_goals(Goal,
BranchPoint - BranchNumSet, RefinedGoals0, RefinedGoals) :-
BranchPoint = branch_point(GoalPath, _),
set__to_sorted_list(BranchNumSet, BranchNums),
list__foldl(unneeded_code__insert_branch_arm_into_refined_goals(
Goal, GoalPath), BranchNums, RefinedGoals0, RefinedGoals).
:- pred unneeded_code__insert_branch_arm_into_refined_goals(hlds_goal::in,
goal_path::in, int::in,
refined_goal_map::in, refined_goal_map::out) is det.
unneeded_code__insert_branch_arm_into_refined_goals(Goal, GoalPath, BranchNum,
RefinedGoals0, RefinedGoals) :-
Key = GoalPath - BranchNum,
( map__search(RefinedGoals0, Key, Goals0) ->
Goals = [Goal | Goals0],
map__det_update(RefinedGoals0, Key, Goals, RefinedGoals)
;
map__det_insert(RefinedGoals0, Key, [Goal], RefinedGoals)
).
%-----------------------------------------------------------------------------%
:- pred unneeded_code__can_eliminate_or_move(hlds_goal::in, instmap::in,
instmap::in, vartypes::in, module_info::in, option_values::in,
where_needed_map::in, where_needed::out) is det.
unneeded_code__can_eliminate_or_move(Goal, InstMap0, InstMap, VarTypes,
ModuleInfo, Options, WhereNeededMap, WhereInfo) :-
instmap_changed_vars(InstMap0, InstMap, VarTypes, ModuleInfo,
ChangedVarSet),
set__to_sorted_list(ChangedVarSet, ChangedVars),
map__init(Empty),
WhereInfo0 = branches(Empty),
Goal = _ - GoalInfo,
goal_info_get_goal_path(GoalInfo, CurrentPath),
list__foldl(
unneeded_code__collect_where_needed(
CurrentPath, WhereNeededMap),
ChangedVars, WhereInfo0, WhereInfo1),
unneeded_code__adjust_where_needed(Goal, Options,
WhereInfo1, WhereInfo).
:- pred unneeded_code__collect_where_needed(goal_path::in,
where_needed_map::in, prog_var::in,
where_needed::in, where_needed::out) is det.
unneeded_code__collect_where_needed(CurrentPath, WhereNeededMap, ChangedVar,
WhereInfo0, WhereInfo) :-
( map__search(WhereNeededMap, ChangedVar, Where) ->
unneeded_code__where_needed_upper_bound(CurrentPath,
Where, WhereInfo0, WhereInfo)
;
WhereInfo = WhereInfo0
).
% This is the predicate responsible for ensuring that the act of optimizing
% away the execution of a goal on some or all computation paths changes the
% operational semantics only in ways that are explicitly permitted by the
% programmer.
:- pred unneeded_code__adjust_where_needed(hlds_goal::in, option_values::in,
where_needed::in, where_needed::out) is det.
unneeded_code__adjust_where_needed(Goal, Options, WhereInfo0, WhereInfo) :-
(
Goal = GoalExpr - GoalInfo,
(
% Do not move goals that can fail, since
% doing so can cause execution to reach goals
% it shouldn't, and those goals may have
% undesirable behavior (e.g. infinite loops).
goal_info_get_determinism(GoalInfo, Detism),
unneeded_code__detism_is_moveable(Detism, no)
;
% Do not move impure or semipure goals,
% since their ordering wrt other such goals
% must be preserved.
goal_info_get_features(GoalInfo, Features),
set__member((impure), Features)
;
% With --fully-strict, we cannot optimize away
% infinite loops or exceptions.
Options^fully_strict = yes,
goal_can_loop_or_throw(Goal)
;
% With --no-reorder-conj, we cannot move
% infinite loops or exceptions, but we can
% delete them.
Options^reorder_conj = no,
goal_can_loop_or_throw(Goal),
WhereInfo0 = branches(BranchMap),
\+ map__is_empty(BranchMap)
;
% Do not delete the `true' goal, since
% deleting it is a no-op, and thus does *not*
% strictly reduce the number of computation
% paths on which a subgoal of the procedure
% body is executed.
GoalExpr = conj([])
;
WhereInfo0 = branches(BranchMap),
map__values(BranchMap, BranchArms),
list__map(set__count, BranchArms, BranchArmCounts),
BranchArmCount = list__foldl(int__plus,
BranchArmCounts, 0),
BranchArmCount > Options^copy_limit
% We may also want to add ither space time tradeoffs.
% E.g. if profiling shows that Goal is required in
% 10 branches that account for 99% of all executions
% and is not required in 5 branches that account for
% the remaining 1%, and Goal itself is sufficiently
% cheap to execute, then not moving Goal may cost
% a small slowdown in 1% of cases but avoid 9 extra
% copies of Goal. Due to better instruction cache
% behavior, not moving Goal may in fact yield faster
% code after all.
)
->
WhereInfo = everywhere
;
WhereInfo = WhereInfo0
).
:- pred unneeded_code__detism_is_moveable(determinism::in, bool::out) is det.
unneeded_code__detism_is_moveable(det, yes).
unneeded_code__detism_is_moveable(semidet, no).
unneeded_code__detism_is_moveable(nondet, no).
unneeded_code__detism_is_moveable(multidet, yes).
unneeded_code__detism_is_moveable(erroneous, no).
unneeded_code__detism_is_moveable(failure, no).
unneeded_code__detism_is_moveable(cc_nondet, no).
unneeded_code__detism_is_moveable(cc_multidet, yes).
%---------------------------------------------------------------------------%
:- pred unneeded_code__demand_inputs(hlds_goal::in, module_info::in,
instmap::in, where_needed::in,
where_needed_map::in, where_needed_map::out) is det.
unneeded_code__demand_inputs(Goal, ModuleInfo, InstMap0, WhereNeeded,
WhereNeededMap0, WhereNeededMap) :-
Goal = _ - GoalInfo,
goal_info_get_nonlocals(GoalInfo, NonLocalSet),
goal_info_get_goal_path(GoalInfo, GoalPath),
set__to_sorted_list(NonLocalSet, NonLocals),
list__filter(unneeded_code__nonlocal_may_be_input(ModuleInfo, InstMap0),
NonLocals, Inputs),
list__foldl(unneeded_code__demand_var(GoalPath, WhereNeeded), Inputs,
WhereNeededMap0, WhereNeededMap).
:- pred unneeded_code__nonlocal_may_be_input(module_info::in, instmap::in,
prog_var::in) is semidet.
unneeded_code__nonlocal_may_be_input(ModuleInfo, InstMap0, Var) :-
instmap__lookup_var(InstMap0, Var, Inst),
inst_is_bound(ModuleInfo, Inst).
%---------------------------------------------------------------------------%
:- pred unneeded_code__undemand_virgin_outputs(hlds_goal::in, module_info::in,
instmap::in, where_needed_map::in, where_needed_map::out) is det.
unneeded_code__undemand_virgin_outputs(Goal, ModuleInfo, InstMap0,
WhereNeededMap0, WhereNeededMap) :-
Goal = _ - GoalInfo,
goal_info_get_nonlocals(GoalInfo, NonLocalSet),
set__to_sorted_list(NonLocalSet, NonLocals),
list__filter(unneeded_code__nonlocal_is_virgin_output(
ModuleInfo, InstMap0), NonLocals, VirginOutputs),
list__foldl(unneeded_code__undemand_var, VirginOutputs,
WhereNeededMap0, WhereNeededMap).
:- pred unneeded_code__nonlocal_is_virgin_output(module_info::in, instmap::in,
prog_var::in) is semidet.
unneeded_code__nonlocal_is_virgin_output(ModuleInfo, InstMap0, Var) :-
instmap__lookup_var(InstMap0, Var, Inst),
\+ inst_is_bound(ModuleInfo, Inst).
%---------------------------------------------------------------------------%
:- pred unneeded_code__demand_var(goal_path::in, where_needed::in,
prog_var::in, where_needed_map::in, where_needed_map::out) is det.
unneeded_code__demand_var(CurrentPath, WhereNeeded, Var,
WhereNeededMap0, WhereNeededMap) :-
( map__search(WhereNeededMap0, Var, Where0) ->
unneeded_code__where_needed_upper_bound(CurrentPath,
WhereNeeded, Where0, Where),
map__det_update(WhereNeededMap0, Var, Where, WhereNeededMap)
;
map__det_insert(WhereNeededMap0, Var, WhereNeeded,
WhereNeededMap)
).
:- pred unneeded_code__undemand_var(prog_var::in,
where_needed_map::in, where_needed_map::out) is det.
unneeded_code__undemand_var(Var, WhereNeededMap0, WhereNeededMap) :-
map__delete(WhereNeededMap0, Var, WhereNeededMap).
%---------------------------------------------------------------------------%
:- pred unneeded_code__demand_var_everywhere(prog_var::in, where_needed::in,
where_needed::out) is det.
unneeded_code__demand_var_everywhere(_Var, _WhereNeeded0, everywhere).
%---------------------------------------------------------------------------%
:- pred unneeded_code__process_goal_internal(hlds_goal::in, hlds_goal::out,
instmap::in, instmap::in, vartypes::in, module_info::in,
option_values::in, where_needed_map::in, where_needed_map::out,
refined_goal_map::in, refined_goal_map::out,
bool::in, bool::out) is det.
unneeded_code__process_goal_internal(Goal0, Goal, InstMap0, InstMap,
VarTypes, ModuleInfo, Options, WhereNeededMap0, WhereNeededMap,
RefinedGoals0, RefinedGoals, Changed0, Changed) :-
Goal0 = GoalExpr0 - GoalInfo0,
% Goal = GoalExpr - GoalInfo,
(
GoalExpr0 = unify(_, _, _, _, _),
Goal = Goal0,
unneeded_code__demand_inputs(Goal, ModuleInfo, InstMap0,
everywhere, WhereNeededMap0, WhereNeededMap),
RefinedGoals = RefinedGoals0,
Changed = Changed0
;
GoalExpr0 = call(_, _, _, _, _, _),
Goal = Goal0,
unneeded_code__demand_inputs(Goal, ModuleInfo, InstMap0,
everywhere, WhereNeededMap0, WhereNeededMap),
RefinedGoals = RefinedGoals0,
Changed = Changed0
;
GoalExpr0 = generic_call(_, _, _, _),
Goal = Goal0,
unneeded_code__demand_inputs(Goal, ModuleInfo, InstMap0,
everywhere, WhereNeededMap0, WhereNeededMap),
RefinedGoals = RefinedGoals0,
Changed = Changed0
;
GoalExpr0 = foreign_proc(_, _, _, _, _, _, _),
Goal = Goal0,
unneeded_code__demand_inputs(Goal, ModuleInfo, InstMap0,
everywhere, WhereNeededMap0, WhereNeededMap),
RefinedGoals = RefinedGoals0,
Changed = Changed0
;
GoalExpr0 = par_conj(_),
Goal = Goal0,
unneeded_code__demand_inputs(Goal, ModuleInfo, InstMap0,
everywhere, WhereNeededMap0, WhereNeededMap),
RefinedGoals = RefinedGoals0,
Changed = Changed0
;
GoalExpr0 = conj(Conjuncts0),
unneeded_code__process_conj(Conjuncts0, Conjuncts,
InstMap0, InstMap, VarTypes, ModuleInfo, Options,
WhereNeededMap0, WhereNeededMap,
RefinedGoals0, RefinedGoals, Changed0, Changed),
GoalExpr = conj(Conjuncts),
Goal = GoalExpr - GoalInfo0
;
GoalExpr0 = switch(SwitchVar, CanFail, Cases0),
(
Cases0 = [case(_, _ - FirstCaseGoalInfo) | _],
goal_info_get_goal_path(FirstCaseGoalInfo,
FirstCaseGoalPath),
FirstCaseGoalPath = [SwitchStep | _],
SwitchStep = switch(_, NumCases)
->
NumAlt = NumCases
;
error("unneeded_code__process_goal_internal: switch count")
),
goal_info_get_goal_path(GoalInfo0, GoalPath),
BranchPoint = branch_point(GoalPath, switch(NumAlt)),
map__map_values(unneeded_code__demand_var_everywhere,
WhereNeededMap0, WhereNeededMap1),
map__init(BranchNeededMap0),
unneeded_code__process_cases(Cases0, BranchPoint, 1,
InstMap0, InstMap, VarTypes, ModuleInfo, Options,
GoalPath, Cases, WhereNeededMap1,
BranchNeededMap0, BranchNeededMap,
RefinedGoals0, RefinedGoals, Changed0, Changed),
unneeded_code__merge_where_needed_maps(GoalPath,
WhereNeededMap1, BranchNeededMap, WhereNeededMap2),
unneeded_code__demand_var(GoalPath, everywhere, SwitchVar,
WhereNeededMap2, WhereNeededMap),
GoalExpr = switch(SwitchVar, CanFail, Cases),
Goal = GoalExpr - GoalInfo0
;
GoalExpr0 = disj(Disjuncts0),
goal_info_get_goal_path(GoalInfo0, GoalPath),
map__map_values(unneeded_code__demand_var_everywhere,
WhereNeededMap0, WhereNeededMap1),
unneeded_code__process_disj(Disjuncts0, InstMap0, InstMap,
VarTypes, ModuleInfo, Options, GoalPath, Disjuncts,
WhereNeededMap1, WhereNeededMap1, WhereNeededMap,
RefinedGoals0, RefinedGoals, Changed0, Changed),
GoalExpr = disj(Disjuncts),
Goal = GoalExpr - GoalInfo0
;
GoalExpr0 = if_then_else(Quant, Cond0, Then0, Else0),
goal_info_get_goal_path(GoalInfo0, GoalPath),
BranchPoint = branch_point(GoalPath, ite),
map__map_values(unneeded_code__demand_var_everywhere,
WhereNeededMap0, WhereNeededMap1),
unneeded_code__process_ite(Cond0, Then0, Else0, BranchPoint,
InstMap0, InstMap, VarTypes, ModuleInfo, Options,
GoalPath, Cond, Then, Else, WhereNeededMap1,
WhereNeededMap, RefinedGoals0, RefinedGoals, Changed0,
Changed),
GoalExpr = if_then_else(Quant, Cond, Then, Else),
Goal = GoalExpr - GoalInfo0
;
GoalExpr0 = not(NegGoal0),
unneeded_code__process_goal(NegGoal0, NegGoal,
InstMap0, InstMap, VarTypes, ModuleInfo, Options,
WhereNeededMap0, WhereNeededMap,
RefinedGoals0, RefinedGoals, Changed0, Changed),
GoalExpr = not(NegGoal),
Goal = GoalExpr - GoalInfo0
;
GoalExpr0 = some(Vars, CanRemove, SomeGoal0),
unneeded_code__process_goal(SomeGoal0, SomeGoal,
InstMap0, InstMap, VarTypes, ModuleInfo, Options,
WhereNeededMap0, WhereNeededMap,
RefinedGoals0, RefinedGoals, Changed0, Changed),
GoalExpr = some(Vars, CanRemove, SomeGoal),
Goal = GoalExpr - GoalInfo0
;
GoalExpr0 = shorthand(_),
error("shorthand in unneeded_code__process_goal_internal")
).
%---------------------------------------------------------------------------%
:- type bracketed_goal
---> bracketed_goal(hlds_goal, instmap, instmap).
:- pred unneeded_code__process_conj(list(hlds_goal)::in, list(hlds_goal)::out,
instmap::in, instmap::in, vartypes::in, module_info::in,
option_values::in, where_needed_map::in, where_needed_map::out,
refined_goal_map::in, refined_goal_map::out,
bool::in, bool::out) is det.
unneeded_code__process_conj(Goals0, Goals, InstMap0, _InstMap, VarTypes,
ModuleInfo, Options, WhereNeededMap0, WhereNeededMap,
RefinedGoals0, RefinedGoals, Changed0, Changed) :-
unneeded_code__build_bracketed_conj(Goals0, InstMap0, BracketedGoals),
list__reverse(BracketedGoals, RevBracketedGoals),
unneeded_code__process_rev_bracketed_conj(RevBracketedGoals, RevGoals,
VarTypes, ModuleInfo, Options, WhereNeededMap0, WhereNeededMap,
RefinedGoals0, RefinedGoals, Changed0, Changed),
list__reverse(RevGoals, Goals).
:- pred unneeded_code__build_bracketed_conj(list(hlds_goal)::in, instmap::in,
list(bracketed_goal)::out) is det.
unneeded_code__build_bracketed_conj([], _, []).
unneeded_code__build_bracketed_conj([Goal | Goals], InstMap0, BracketedGoals)
:-
( instmap__is_unreachable(InstMap0) ->
BracketedGoals = []
;
Goal = _ - GoalInfo,
goal_info_get_instmap_delta(GoalInfo, InstMapDelta),
instmap__apply_instmap_delta(InstMap0, InstMapDelta, InstMap1),
unneeded_code__build_bracketed_conj(Goals, InstMap1,
BracketedTail),
BracketedGoal = bracketed_goal(Goal, InstMap0, InstMap1),
BracketedGoals = [BracketedGoal | BracketedTail]
).
:- pred unneeded_code__process_rev_bracketed_conj(list(bracketed_goal)::in,
list(hlds_goal)::out, vartypes::in, module_info::in, option_values::in,
where_needed_map::in, where_needed_map::out,
refined_goal_map::in, refined_goal_map::out,
bool::in, bool::out) is det.
unneeded_code__process_rev_bracketed_conj([], [], _, _, _,
WhereNeededMap, WhereNeededMap,
RefinedGoals, RefinedGoals, Changed, Changed).
unneeded_code__process_rev_bracketed_conj([BracketedGoal | BracketedGoals],
Goals, VarTypes, ModuleInfo, Options, WhereNeededMap0,
WhereNeededMap, RefinedGoals0, RefinedGoals, Changed0,
Changed) :-
BracketedGoal = bracketed_goal(Goal0, InstMap0, InstMap),
unneeded_code__process_goal(Goal0, Goal1, InstMap0, InstMap,
VarTypes, ModuleInfo, Options, WhereNeededMap0, WhereNeededMap1,
RefinedGoals0, RefinedGoals1, Changed0, Changed1),
unneeded_code__process_rev_bracketed_conj(BracketedGoals, Goals1,
VarTypes, ModuleInfo, Options, WhereNeededMap1, WhereNeededMap,
RefinedGoals1, RefinedGoals, Changed1, Changed),
( true_goal(Goal1) ->
Goals = Goals1
;
Goals = [Goal1 | Goals1]
).
%---------------------------------------------------------------------------%
:- pred unneeded_code__process_disj(list(hlds_goal)::in, instmap::in,
instmap::in, vartypes::in, module_info::in, option_values::in,
goal_path::in, list(hlds_goal)::out,
where_needed_map::in, where_needed_map::in, where_needed_map::out,
refined_goal_map::in, refined_goal_map::out,
bool::in, bool::out) is det.
unneeded_code__process_disj([], _, _, _, _, _, _, [],
_, WhereNeededMap, WhereNeededMap,
RefinedGoals, RefinedGoals, Changed, Changed).
unneeded_code__process_disj([Goal0 | Goals0], InstMap0, InstMap, VarTypes,
ModuleInfo, Options, CurrentPath, [Goal | Goals],
StartWhereNeededMap, WhereNeededMap0, WhereNeededMap,
RefinedGoals0, RefinedGoals, Changed0, Changed) :-
unneeded_code__process_goal(Goal0, Goal, InstMap0, InstMap, VarTypes,
ModuleInfo, Options, StartWhereNeededMap, WhereNeededMapFirst,
RefinedGoals0, RefinedGoals1, Changed0, Changed1),
map__to_assoc_list(WhereNeededMapFirst, WhereNeededList),
unneeded_code__add_where_needed_list(WhereNeededList, CurrentPath,
WhereNeededMap0, WhereNeededMap1),
unneeded_code__process_disj(Goals0, InstMap0, InstMap, VarTypes,
ModuleInfo, Options, CurrentPath, Goals,
StartWhereNeededMap, WhereNeededMap1, WhereNeededMap,
RefinedGoals1, RefinedGoals, Changed1, Changed).
%---------------------------------------------------------------------------%
:- pred unneeded_code__process_cases(list(case)::in, branch_point::in, int::in,
instmap::in, instmap::in, vartypes::in, module_info::in,
option_values::in, goal_path::in, list(case)::out, where_needed_map::in,
where_needed_map::in, where_needed_map::out,
refined_goal_map::in, refined_goal_map::out,
bool::in, bool::out) is det.
unneeded_code__process_cases([], _, _, _, _, _, _, _, _, [],
_, WhereNeededMap, WhereNeededMap,
RefinedGoals, RefinedGoals, Changed, Changed).
unneeded_code__process_cases([case(Var, Goal0) | Cases0],
BranchPoint, BranchNum, InstMap0, InstMap,
VarTypes, ModuleInfo, Options, CurrentPath,
[case(Var, Goal) | Cases], StartWhereNeededMap,
WhereNeededMap0, WhereNeededMap,
RefinedGoals0, RefinedGoals, Changed0, Changed) :-
unneeded_code__process_goal(Goal0, Goal, InstMap0, InstMap, VarTypes,
ModuleInfo, Options, StartWhereNeededMap, WhereNeededMapFirst,
RefinedGoals0, RefinedGoals1, Changed0, Changed1),
map__to_assoc_list(WhereNeededMapFirst, WhereNeededList),
unneeded_code__add_alt_start(WhereNeededList, BranchPoint, BranchNum,
CurrentPath, WhereNeededMap0, WhereNeededMap1),
unneeded_code__process_cases(Cases0, BranchPoint, BranchNum + 1,
InstMap0, InstMap, VarTypes, ModuleInfo, Options, CurrentPath,
Cases, StartWhereNeededMap, WhereNeededMap1, WhereNeededMap,
RefinedGoals1, RefinedGoals, Changed1, Changed).
%---------------------------------------------------------------------------%
:- pred unneeded_code__process_ite(hlds_goal::in, hlds_goal::in, hlds_goal::in,
branch_point::in, instmap::in, instmap::in, vartypes::in,
module_info::in, option_values::in, goal_path::in,
hlds_goal::out, hlds_goal::out, hlds_goal::out,
where_needed_map::in, where_needed_map::out,
refined_goal_map::in, refined_goal_map::out,
bool::in, bool::out) is det.
unneeded_code__process_ite(Cond0, Then0, Else0, BranchPoint,
InstMap0, InstMap, VarTypes, ModuleInfo, Options, CurrentPath,
Cond, Then, Else, WhereNeededMap0, WhereNeededMap,
RefinedGoals0, RefinedGoals, Changed0, Changed) :-
Cond0 = _ - CondInfo0,
goal_info_get_instmap_delta(CondInfo0, InstMapDelta),
instmap__apply_instmap_delta(InstMap0, InstMapDelta, InstMapCond),
unneeded_code__process_goal(Else0, Else, InstMap0, InstMap, VarTypes,
ModuleInfo, Options, WhereNeededMap0, WhereNeededMapElse,
RefinedGoals0, RefinedGoals1, Changed0, Changed1),
unneeded_code__process_goal(Then0, Then, InstMapCond, InstMap,
VarTypes, ModuleInfo, Options, WhereNeededMap0,
WhereNeededMapThen, RefinedGoals1, RefinedGoals2, Changed1,
Changed2),
map__init(BranchNeededMap0),
map__to_assoc_list(WhereNeededMapElse, WhereNeededListElse),
unneeded_code__add_alt_start(WhereNeededListElse, BranchPoint, 2,
CurrentPath, BranchNeededMap0, BranchNeededMap1),
map__to_assoc_list(WhereNeededMapThen, WhereNeededListThen),
unneeded_code__add_alt_start(WhereNeededListThen, BranchPoint, 1,
CurrentPath, BranchNeededMap1, BranchNeededMap),
unneeded_code__merge_where_needed_maps(CurrentPath,
WhereNeededMap0, BranchNeededMap, WhereNeededMapCond),
unneeded_code__process_goal(Cond0, Cond, InstMap0, InstMapCond,
VarTypes, ModuleInfo, Options, WhereNeededMapCond,
WhereNeededMap, RefinedGoals2, RefinedGoals, Changed2, Changed).
%---------------------------------------------------------------------------%
% Merge two where_needed_maps, so that if var V is needed at branch B
% in the resulting where_needed_map iff it is needed there in one of the input
% maps.
:- pred unneeded_code__merge_where_needed_maps(goal_path::in,
where_needed_map::in, where_needed_map::in, where_needed_map::out)
is det.
unneeded_code__merge_where_needed_maps(CurrentPath,
WhereNeededMap1, WhereNeededMap2, WhereNeededMap) :-
map__to_assoc_list(WhereNeededMap1, WhereNeededList1),
unneeded_code__add_where_needed_list(WhereNeededList1, CurrentPath,
WhereNeededMap2, WhereNeededMap).
:- pred unneeded_code__add_where_needed_list(
assoc_list(prog_var, where_needed)::in, goal_path::in,
where_needed_map::in, where_needed_map::out) is det.
unneeded_code__add_where_needed_list([], _, WhereNeededMap, WhereNeededMap).
unneeded_code__add_where_needed_list([Var - BranchWhere | WhereNeededList],
CurrentPath, WhereNeededMap0, WhereNeededMap) :-
( map__search(WhereNeededMap0, Var, OldWhere) ->
unneeded_code__where_needed_upper_bound(CurrentPath,
BranchWhere, OldWhere, CombinedWhere),
map__det_update(WhereNeededMap0, Var, CombinedWhere,
WhereNeededMap1)
;
map__det_insert(WhereNeededMap0, Var, BranchWhere,
WhereNeededMap1)
),
unneeded_code__add_where_needed_list(WhereNeededList, CurrentPath,
WhereNeededMap1, WhereNeededMap).
% Given a where_needed_map, add to it the where_needed information for the
% start of an alternative in a branched goal. This source is important,
% because if the analysis *at the start of an alternative* says that the
% variable is needed everywhere, the scope of this "everywhere" is only
% that alternative.
:- pred unneeded_code__add_alt_start(assoc_list(prog_var, where_needed)::in,
branch_point::in, int::in, goal_path::in,
where_needed_map::in, where_needed_map::out) is det.
unneeded_code__add_alt_start([], _, _, _, WhereNeededMap, WhereNeededMap).
unneeded_code__add_alt_start([Var - BranchWhere0 | WhereNeededList],
BranchPoint, BranchNum, CurrentPath,
WhereNeededMap0, WhereNeededMap) :-
(
BranchWhere0 = everywhere,
map__init(Empty),
set__singleton_set(BranchNumSet, BranchNum),
map__det_insert(Empty, BranchPoint, BranchNumSet, BranchMap),
BranchWhere = branches(BranchMap)
;
BranchWhere0 = branches(_),
BranchWhere = BranchWhere0
),
( map__search(WhereNeededMap0, Var, OldWhere) ->
unneeded_code__where_needed_upper_bound(CurrentPath,
BranchWhere, OldWhere, CombinedWhere),
map__det_update(WhereNeededMap0, Var, CombinedWhere,
WhereNeededMap1)
;
map__det_insert(WhereNeededMap0, Var, BranchWhere,
WhereNeededMap1)
),
unneeded_code__add_alt_start(WhereNeededList, BranchPoint, BranchNum,
CurrentPath, WhereNeededMap1, WhereNeededMap).
%---------------------------------------------------------------------------%
:- pred unneeded_code__refine_goal(hlds_goal::in, refined_goal_map::in,
hlds_goal::out, refined_goal_map::out) is det.
unneeded_code__refine_goal(Goal0, RefinedGoals0, Goal, RefinedGoals) :-
Goal0 = GoalExpr0 - GoalInfo0,
(
GoalExpr0 = unify(_, _, _, _, _),
Goal = Goal0,
RefinedGoals = RefinedGoals0
;
GoalExpr0 = call(_, _, _, _, _, _),
Goal = Goal0,
RefinedGoals = RefinedGoals0
;
GoalExpr0 = generic_call(_, _, _, _),
Goal = Goal0,
RefinedGoals = RefinedGoals0
;
GoalExpr0 = foreign_proc(_, _, _, _, _, _, _),
Goal = Goal0,
RefinedGoals = RefinedGoals0
;
GoalExpr0 = par_conj(_),
Goal = Goal0,
RefinedGoals = RefinedGoals0
;
GoalExpr0 = conj(Conjuncts0),
unneeded_code__refine_conj(Conjuncts0, RefinedGoals0,
Conjuncts, RefinedGoals),
GoalExpr = conj(Conjuncts),
Goal = GoalExpr - GoalInfo0
;
GoalExpr0 = switch(SwitchVar, CanFail, Cases0),
goal_info_get_goal_path(GoalInfo0, GoalPath),
unneeded_code__refine_cases(Cases0, RefinedGoals0,
GoalPath, 1, Cases, RefinedGoals),
GoalExpr = switch(SwitchVar, CanFail, Cases),
Goal = GoalExpr - GoalInfo0
;
GoalExpr0 = disj(Disjuncts0),
goal_info_get_goal_path(GoalInfo0, GoalPath),
unneeded_code__refine_disj(Disjuncts0, RefinedGoals0,
GoalPath, 1, Disjuncts, RefinedGoals),
GoalExpr = disj(Disjuncts),
Goal = GoalExpr - GoalInfo0
;
GoalExpr0 = if_then_else(Quant, Cond0, Then0, Else0),
goal_info_get_goal_path(GoalInfo0, GoalPath),
unneeded_code__refine_ite(Cond0, Then0, Else0, RefinedGoals0,
GoalPath, Cond, Then, Else, RefinedGoals),
GoalExpr = if_then_else(Quant, Cond, Then, Else),
Goal = GoalExpr - GoalInfo0
;
GoalExpr0 = not(NegGoal0),
unneeded_code__refine_goal(NegGoal0, RefinedGoals0,
NegGoal, RefinedGoals),
GoalExpr = not(NegGoal),
Goal = GoalExpr - GoalInfo0
;
GoalExpr0 = some(Vars, CanFail, SomeGoal0),
unneeded_code__refine_goal(SomeGoal0, RefinedGoals0,
SomeGoal, RefinedGoals),
GoalExpr = some(Vars, CanFail, SomeGoal),
Goal = GoalExpr - GoalInfo0
;
GoalExpr0 = shorthand(_),
error("shorthand in unneeded_code__refine_goal")
).
:- pred unneeded_code__refine_conj(list(hlds_goal)::in, refined_goal_map::in,
list(hlds_goal)::out, refined_goal_map::out) is det.
unneeded_code__refine_conj([], RefinedGoals, [], RefinedGoals).
unneeded_code__refine_conj([Goal0 | Goals0], RefinedGoals0, Goals,
RefinedGoals) :-
unneeded_code__refine_goal(Goal0, RefinedGoals0, HeadGoal,
RefinedGoals1),
unneeded_code__refine_conj(Goals0, RefinedGoals1, TailGoals,
RefinedGoals),
( HeadGoal = conj(HeadGoals) - _ ->
list__append(HeadGoals, TailGoals, Goals)
;
Goals = [HeadGoal | TailGoals]
).
:- pred unneeded_code__refine_cases(list(case)::in, refined_goal_map::in,
goal_path::in, int::in, list(case)::out, refined_goal_map::out) is det.
unneeded_code__refine_cases([], RefinedGoals, _, _, [], RefinedGoals).
unneeded_code__refine_cases([case(Var, Goal0) | Cases0], RefinedGoals0,
GoalPath, BranchNum,
[case(Var, Goal) | Cases], RefinedGoals) :-
unneeded_code__refine_goal(Goal0, RefinedGoals0, Goal1, RefinedGoals1),
( map__search(RefinedGoals1, GoalPath - BranchNum, ToInsertGoals) ->
unneeded_code__insert_refine_goals(ToInsertGoals, Goal1, Goal),
map__delete(RefinedGoals1, GoalPath - BranchNum, RefinedGoals2)
;
Goal = Goal1,
RefinedGoals2 = RefinedGoals1
),
unneeded_code__refine_cases(Cases0, RefinedGoals2,
GoalPath, BranchNum + 1, Cases, RefinedGoals).
:- pred unneeded_code__refine_disj(list(hlds_goal)::in, refined_goal_map::in,
goal_path::in, int::in, list(hlds_goal)::out, refined_goal_map::out)
is det.
unneeded_code__refine_disj([], RefinedGoals, _, _, [], RefinedGoals).
unneeded_code__refine_disj([Goal0 | Goals0], RefinedGoals0,
GoalPath, BranchNum, [Goal | Goals], RefinedGoals) :-
unneeded_code__refine_goal(Goal0, RefinedGoals0, Goal1, RefinedGoals1),
( map__search(RefinedGoals1, GoalPath - BranchNum, ToInsertGoals) ->
unneeded_code__insert_refine_goals(ToInsertGoals, Goal1, Goal),
map__delete(RefinedGoals1, GoalPath - BranchNum, RefinedGoals2)
;
Goal = Goal1,
RefinedGoals2 = RefinedGoals1
),
unneeded_code__refine_disj(Goals0, RefinedGoals2,
GoalPath, BranchNum + 1, Goals, RefinedGoals).
:- pred unneeded_code__refine_ite(hlds_goal::in, hlds_goal::in, hlds_goal::in,
refined_goal_map::in, goal_path::in,
hlds_goal::out, hlds_goal::out, hlds_goal::out, refined_goal_map::out)
is det.
unneeded_code__refine_ite(Cond0, Then0, Else0, RefinedGoals0, GoalPath,
Cond, Then, Else, RefinedGoals) :-
unneeded_code__refine_goal(Cond0, RefinedGoals0, Cond, RefinedGoals1),
unneeded_code__refine_goal(Then0, RefinedGoals1, Then1, RefinedGoals2),
unneeded_code__refine_goal(Else0, RefinedGoals2, Else1, RefinedGoals3),
( map__search(RefinedGoals3, GoalPath - 1, ToInsertGoalsThen) ->
unneeded_code__insert_refine_goals(ToInsertGoalsThen, Then1,
Then),
map__delete(RefinedGoals3, GoalPath - 1, RefinedGoals4)
;
Then = Then1,
RefinedGoals4 = RefinedGoals3
),
( map__search(RefinedGoals4, GoalPath - 2, ToInsertGoalsElse) ->
unneeded_code__insert_refine_goals(ToInsertGoalsElse, Else1,
Else),
map__delete(RefinedGoals4, GoalPath - 2, RefinedGoals)
;
Else = Else1,
RefinedGoals = RefinedGoals4
).
:- pred unneeded_code__insert_refine_goals(list(hlds_goal)::in, hlds_goal::in,
hlds_goal::out) is det.
unneeded_code__insert_refine_goals(ToInsertGoals, Goal0, Goal) :-
list__append(ToInsertGoals, [Goal0], Conj),
% XXX GoalInfo0
Goal0 = _ - GoalInfo0,
conj_list_to_goal(Conj, GoalInfo0, Goal).
%-----------------------------------------------------------------------------%
% Given two sets of requirements about where a goal is needed, return a single
% requirement that contains all the demands. The main purpose of this predicate
% is to discover when the union of two sets of requirements (e.g. branch sets
% {b1,b2} and {b3} covers all computation paths.
:- pred unneeded_code__where_needed_upper_bound(goal_path::in,
where_needed::in, where_needed::in, where_needed::out) is det.
unneeded_code__where_needed_upper_bound(CurrentPath,
WhereNeededA, WhereNeededB, WhereNeeded) :-
(
WhereNeededA = everywhere,
WhereNeeded = everywhere
;
WhereNeededA = branches(BranchesA),
(
WhereNeededB = everywhere,
WhereNeeded = everywhere
;
WhereNeededB = branches(BranchesB),
unneeded_code__where_needed_branches_upper_bound(
CurrentPath, BranchesA, BranchesB, WhereNeeded)
)
).
:- pred unneeded_code__where_needed_branches_upper_bound(goal_path::in,
where_needed_branches::in, where_needed_branches::in,
where_needed::out) is det.
unneeded_code__where_needed_branches_upper_bound(CurrentPath,
BranchesA, BranchesB, WhereNeeded) :-
% should select smaller map to convert to list
map__to_assoc_list(BranchesA, BranchesList),
unneeded_code__where_needed_branches_upper_bound_2(CurrentPath,
BranchesList, BranchesB, WhereNeeded).
:- pred unneeded_code__where_needed_branches_upper_bound_2(goal_path::in,
assoc_list(branch_point, set(int))::in, where_needed_branches::in,
where_needed::out) is det.
unneeded_code__where_needed_branches_upper_bound_2(_, [],
Branches, branches(Branches)).
unneeded_code__where_needed_branches_upper_bound_2(CurrentPath, [First | Rest],
Branches0, WhereNeeded) :-
First = BranchPoint - NewAlts,
( map__search(Branches0, BranchPoint, OldAlts) ->
set__union(OldAlts, NewAlts, Alts),
BranchPoint = branch_point(GoalPath, BranchAlts),
( unneeded_code__branch_point_is_complete(BranchAlts, Alts) ->
(
unneeded_code__get_parent_branch_point(GoalPath,
ParentGoalPath, ParentGoalPathStep,
ParentBranchAlt, ParentBranchNum),
\+ list__remove_suffix(CurrentPath,
[ParentGoalPathStep | ParentGoalPath],
_)
->
map__delete(Branches0, BranchPoint, Branches1),
ParentBranchPoint = branch_point(
ParentGoalPath, ParentBranchAlt),
set__singleton_set(ParentAlts,
ParentBranchNum),
unneeded_code__where_needed_branches_upper_bound_2(
CurrentPath,
[ParentBranchPoint - ParentAlts
| Rest],
Branches1, WhereNeeded)
;
WhereNeeded = everywhere
)
;
map__det_update(Branches0, BranchPoint, Alts,
Branches1),
unneeded_code__where_needed_branches_upper_bound_2(
CurrentPath, Rest, Branches1, WhereNeeded)
)
;
map__det_insert(Branches0, BranchPoint, NewAlts, Branches1),
unneeded_code__where_needed_branches_upper_bound_2(CurrentPath,
Rest, Branches1, WhereNeeded)
).
:- pred unneeded_code__get_parent_branch_point(goal_path::in, goal_path::out,
goal_path_step::out, branch_alts::out, int::out) is semidet.
unneeded_code__get_parent_branch_point([First | Rest], Parent, ParentStep,
BranchAlt, BranchNum) :-
( First = switch(Arm, NumAlts) ->
Parent = Rest,
ParentStep = First,
BranchAlt = switch(NumAlts),
BranchNum = Arm
; First = ite_then ->
Parent = Rest,
ParentStep = First,
BranchAlt = ite,
BranchNum = 1
; First = ite_else ->
Parent = Rest,
ParentStep = First,
BranchAlt = ite,
BranchNum = 2
;
unneeded_code__get_parent_branch_point(Rest, Parent, ParentStep,
BranchAlt, BranchNum)
).
:- pred unneeded_code__branch_point_is_complete(branch_alts::in, set(int)::in)
is semidet.
unneeded_code__branch_point_is_complete(ite, Alts) :-
set__count(Alts, NumAlts),
NumAlts = 2.
unneeded_code__branch_point_is_complete(switch(NumFunctors), Alts) :-
set__count(Alts, NumAlts),
NumAlts = NumFunctors.
%---------------------------------------------------------------------------%