mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 01:13:30 +00:00
compiler/hlds_pred.m:
This module used to maintain a distinction between valid and invalid
procedures in a pred_info. The distinction was based on whether the
proc_info field containing a list of mode_error_infos was empty
(such procedures were valid) or nonempty (such procedures were invalid).
This field was used only during the early phases of the compiler
from mode analysis to unique mode analysis, but all later passes
had to check whether the field was empty before processing the procedure.
This diff deletes this field from proc_infos. The information that this
field used to contain is now stored in *temporary* data structures
maintained and used only by the mode and unique mode analysis phases.
These phases use the code they share in modes.m to delete all invalid
procedures from the HLDS before they hand over that HLDS to other phases.
This means that outside these two compiler phases, *all* procedures in the
HLDS will be valid.
Delete all service predicates and functions that tested procedures
for validity, since this has now become a meaningless test. In one case,
where there was no non-validity-testing equivalent, make one.
compiler/mode_info.m:
Define the proc_mode_error_map, which effectively replaces the fields
deleted from proc_infos. Define the operations on it that we need.
compiler/modes.m:
Initialize proc_mode_error_maps to empty, and then pass them through
mode analysis as part of the mode_info, allowing mode analysis code
to use it to check procedure validity.
When a mode analysis phase (either ordinary or unique mode analysis)
is done, delete the procedures that we have now detected are invalid.
However, before we do, print any inference messages about them.
compiler/unique_modes.m:
Use the new field in mode_info to check procedures' validity.
Delete the unique_modes_check_proc predicate, because it had
only one caller in modes.m, which called another predicate in modes.m
through it.
compiler/modecheck_call.m:
compiler/modecheck_unify.m:
Use the new field in mode_info to check procedures' validity.
compiler/try_expand.m:
Conform to the changes above.
When a mode check of a procedure repeated after try expansion finds
an error, delete the now-detected-to-be-invalid procedure.
compiler/cse_detection.m:
Conform to the changes above.
When a mode check of a procedure repeated after common subexpression
eliminate finds an error, don't bother to delete the now-detected-to-be-
invalid procedure, because the code on that path throws an exception
anyway.
Fix an old incongruity: one trace goal created a new ProgressStream
in a predicate that would have been given existing one if needed.
compiler/direct_arg_in_out.m:
Conform to the changes above by deleting a validity test.
Delete a predicate that had no job *except* that validity test.
compiler/style_checks.m:
Use missing procedure ids to detect invalid procedures. Add an XXX
about a limitation of this approach.
compiler/bytecode_gen.m:
compiler/dead_proc_elim.m:
compiler/deep_profiling.m:
compiler/delay_partial_inst.m:
compiler/dep_par_conj.m:
compiler/det_analysis.m:
compiler/distance_granularity.m:
compiler/exception_analysis.m:
compiler/float_regs.m:
compiler/goal_mode.m:
compiler/higher_order.m:
compiler/hlds_call_tree.m:
compiler/hlds_dependency_graph.m:
compiler/hlds_out_pred.m:
compiler/intermod.m:
compiler/intermod_analysis.m:
compiler/introduce_parallelism.m:
compiler/lambda.m:
compiler/liveness.m:
compiler/mark_tail_calls.m:
compiler/mercury_compile_front_end.m:
compiler/mercury_compile_llds_back_end.m:
compiler/ml_proc_gen.m:
compiler/passes_aux.m:
compiler/pd_util.m:
compiler/polymorphism.m:
compiler/polymorphism_goal.m:
compiler/proc_gen.m:
compiler/purity.m:
compiler/rbmm.condition_renaming.m:
compiler/rbmm.execution_path.m:
compiler/rbmm.live_region_analysis.m:
compiler/rbmm.live_variable_analysis.m:
compiler/rbmm.points_to_analysis.m:
compiler/rbmm.region_arguments.m:
compiler/rbmm.region_instruction.m:
compiler/rbmm.region_transformation.m:
compiler/ssdebug.m:
compiler/stm_expand.m:
compiler/stratify.m:
compiler/structure_reuse.analysis.m:
compiler/structure_reuse.direct.m:
compiler/structure_reuse.domain.m:
compiler/structure_sharing.analysis.m:
compiler/structure_sharing.domain.m:
compiler/switch_detection.m:
compiler/table_gen.m:
compiler/tabling_analysis.m:
compiler/term_constr_initial.m:
compiler/termination.m:
compiler/trailing_analysis.m:
compiler/untupling.m:
compiler/unused_args.m:
Conform to the changes above, mostly by deleting validity tests.
396 lines
16 KiB
Mathematica
396 lines
16 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2005-2007, 2010-2011 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.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File rbmm.live_variable_analysis.m.
|
|
% Main author: Quan Phan.
|
|
%
|
|
% This module implements the live variable analysis.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module transform_hlds.rbmm.live_variable_analysis.
|
|
:- interface.
|
|
|
|
:- import_module hlds.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module transform_hlds.rbmm.region_liveness_info.
|
|
|
|
% Collects live variable sets.
|
|
%
|
|
:- pred live_variable_analysis(module_info::in, execution_path_table::in,
|
|
proc_pp_varset_table::out, proc_pp_varset_table::out,
|
|
proc_pp_varset_table::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.var_table.
|
|
:- import_module transform_hlds.smm_common.
|
|
|
|
:- import_module assoc_list.
|
|
:- import_module bool.
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module pair.
|
|
:- import_module require.
|
|
:- import_module set.
|
|
:- import_module string.
|
|
:- import_module term.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Live variable analysis
|
|
%
|
|
|
|
% For each procedure, compute the sets of live variables before and after
|
|
% each program point.
|
|
% Currently, it also calculates set of void variables (i.e., ones whose names
|
|
% start with "_") after each program point. Those variables are considered
|
|
% dead at that point.
|
|
%
|
|
|
|
live_variable_analysis(ModuleInfo, ExecPathTable, LVBeforeTable,
|
|
LVAfterTable, VoidVarTable) :-
|
|
module_info_get_valid_pred_ids(ModuleInfo, PredIds),
|
|
map.init(LVBeforeTable0),
|
|
map.init(LVAfterTable0),
|
|
map.init(VoidVarTable0),
|
|
list.foldl3(live_variable_analysis_pred(ModuleInfo, ExecPathTable),
|
|
PredIds, LVBeforeTable0, LVBeforeTable, LVAfterTable0, LVAfterTable,
|
|
VoidVarTable0, VoidVarTable).
|
|
|
|
:- pred live_variable_analysis_pred(module_info::in, execution_path_table::in,
|
|
pred_id::in, proc_pp_varset_table::in, proc_pp_varset_table::out,
|
|
proc_pp_varset_table::in, proc_pp_varset_table::out,
|
|
proc_pp_varset_table::in, proc_pp_varset_table::out) is det.
|
|
|
|
live_variable_analysis_pred(ModuleInfo, ExecPathTable, PredId,
|
|
!LVBeforeTable, !LVAfterTable, !VoidVarTable) :-
|
|
module_info_pred_info(ModuleInfo, PredId, PredInfo),
|
|
ProcIds = pred_info_all_non_imported_procids(PredInfo),
|
|
list.foldl3(
|
|
live_variable_analysis_proc(ModuleInfo, ExecPathTable, PredId),
|
|
ProcIds, !LVBeforeTable, !LVAfterTable, !VoidVarTable).
|
|
|
|
:- pred live_variable_analysis_proc(module_info::in,
|
|
execution_path_table::in, pred_id::in, proc_id::in,
|
|
proc_pp_varset_table::in, proc_pp_varset_table::out,
|
|
proc_pp_varset_table::in, proc_pp_varset_table::out,
|
|
proc_pp_varset_table::in, proc_pp_varset_table::out) is det.
|
|
|
|
live_variable_analysis_proc(ModuleInfo, ExecPathTable, PredId, ProcId,
|
|
!LVBeforeTable, !LVAfterTable, !VoidVarTable) :-
|
|
PPId = proc(PredId, ProcId),
|
|
( if some_are_special_preds([PPId], ModuleInfo) then
|
|
true
|
|
else
|
|
module_info_proc_info(ModuleInfo, PPId, ProcInfo),
|
|
find_input_output_args(ModuleInfo, ProcInfo, Inputs, Outputs),
|
|
map.lookup(ExecPathTable, PPId, ExecPaths),
|
|
live_variable_analysis_exec_paths(ExecPaths, Inputs, Outputs,
|
|
ModuleInfo, ProcInfo, map.init, ProcLVBefore,
|
|
map.init, ProcLVAfter, map.init, ProcVoidVar),
|
|
|
|
map.set(PPId, ProcLVBefore, !LVBeforeTable),
|
|
map.set(PPId, ProcLVAfter, !LVAfterTable),
|
|
map.set(PPId, ProcVoidVar, !VoidVarTable)
|
|
).
|
|
|
|
:- pred live_variable_analysis_exec_paths(list(execution_path)::in,
|
|
list(prog_var)::in, list(prog_var)::in, module_info::in, proc_info::in,
|
|
pp_varset_table::in, pp_varset_table::out, pp_varset_table::in,
|
|
pp_varset_table::out, pp_varset_table::in, pp_varset_table::out) is det.
|
|
|
|
% Live variable analysis is backward, so we reverse the execution path
|
|
% before starting. We have specific treatment for execution paths with
|
|
% only one program point, which means the last program point is also the
|
|
% first one.
|
|
%
|
|
live_variable_analysis_exec_paths([], _, _, _, _, !ProcLVBefore,
|
|
!ProcLVAfter, !ProcVoidVar).
|
|
live_variable_analysis_exec_paths([ExecPath0 | ExecPaths], Inputs, Outputs,
|
|
ModuleInfo, ProcInfo, !ProcLVBefore, !ProcLVAfter, !ProcVoidVar) :-
|
|
list.reverse(ExecPath0, ExecPath),
|
|
( if list.length(ExecPath) = 1 then
|
|
live_variable_analysis_singleton_exec_path(ExecPath, Inputs, Outputs,
|
|
ModuleInfo, ProcInfo, !ProcLVBefore, !ProcLVAfter, !ProcVoidVar)
|
|
else
|
|
% Start with the last program point.
|
|
live_variable_analysis_exec_path(ExecPath, Inputs, Outputs,
|
|
ModuleInfo, ProcInfo, yes, set.init, !ProcLVBefore, !ProcLVAfter,
|
|
!ProcVoidVar)
|
|
),
|
|
live_variable_analysis_exec_paths(ExecPaths, Inputs, Outputs,
|
|
ModuleInfo, ProcInfo, !ProcLVBefore, !ProcLVAfter, !ProcVoidVar).
|
|
|
|
:- pred live_variable_analysis_exec_path(execution_path::in,
|
|
list(prog_var)::in, list(prog_var)::in, module_info::in, proc_info::in,
|
|
bool::in, set(prog_var)::in, pp_varset_table::in, pp_varset_table::out,
|
|
pp_varset_table::in, pp_varset_table::out,
|
|
pp_varset_table::in, pp_varset_table::out) is det.
|
|
|
|
live_variable_analysis_exec_path([], _, _, _, _,_, _, !ProcLVBefore,
|
|
!ProcLVAfter, !ProcVoidVar).
|
|
% XXX Exactly what piece of code does this comment apply to?
|
|
% Process the last program point in an execution path. The live variable
|
|
% set of the last program point is always the set of output variables
|
|
% of the procedure.
|
|
%
|
|
live_variable_analysis_exec_path([(LastProgPoint - Goal) | ProgPointGoals],
|
|
Inputs, Outputs, ModuleInfo, ProcInfo, yes, _LVBeforeNext,
|
|
!ProcLVBefore, !ProcLVAfter, !ProcVoidVar) :-
|
|
( if map.search(!.ProcLVAfter, LastProgPoint, LVAfterLast0) then
|
|
LVAfterLast = LVAfterLast0
|
|
else
|
|
LVAfterLast = set.list_to_set(Outputs),
|
|
map.set(LastProgPoint, LVAfterLast, !ProcLVAfter)
|
|
),
|
|
|
|
% Compute live variable before this last program point.
|
|
compute_useds_produceds(ModuleInfo, Goal, UsedSet, ProducedSet),
|
|
set.union(set.difference(LVAfterLast, ProducedSet), UsedSet,
|
|
LVBeforeLastInThisExecPath),
|
|
record_live_vars_at_prog_point(LastProgPoint, LVBeforeLastInThisExecPath,
|
|
!ProcLVBefore),
|
|
|
|
% Collect void variables after this program point.
|
|
collect_void_vars(LastProgPoint, ProducedSet, ProcInfo, !ProcVoidVar),
|
|
|
|
live_variable_analysis_exec_path(ProgPointGoals, Inputs, Outputs,
|
|
ModuleInfo, ProcInfo, no, LVBeforeLastInThisExecPath, !ProcLVBefore,
|
|
!ProcLVAfter, !ProcVoidVar).
|
|
|
|
% Process a middle program point.
|
|
%
|
|
live_variable_analysis_exec_path(
|
|
[(ProgPoint - Goal), ProgPointGoal | ProgPointGoals], Inputs,
|
|
Outputs, ModuleInfo, ProcInfo, no, LVBeforeNext, !ProcLVBefore,
|
|
!ProcLVAfter, !ProcVoidVar) :-
|
|
% The live variable set after this program point is the union of the
|
|
% live variable sets after it in all execution paths to which it belongs.
|
|
record_live_vars_at_prog_point(ProgPoint, LVBeforeNext, !ProcLVAfter),
|
|
|
|
% Compute LV before this program point.
|
|
compute_useds_produceds(ModuleInfo, Goal, UsedSet, ProducedSet),
|
|
set.union(set.difference(LVBeforeNext, ProducedSet), UsedSet,
|
|
LVBeforeInThisExecPath),
|
|
record_live_vars_at_prog_point(ProgPoint, LVBeforeInThisExecPath,
|
|
!ProcLVBefore),
|
|
|
|
% Collect void variables after this program point.
|
|
collect_void_vars(ProgPoint, ProducedSet, ProcInfo, !ProcVoidVar),
|
|
|
|
live_variable_analysis_exec_path([ProgPointGoal | ProgPointGoals],
|
|
Inputs, Outputs, ModuleInfo, ProcInfo, no, LVBeforeInThisExecPath,
|
|
!ProcLVBefore, !ProcLVAfter, !ProcVoidVar).
|
|
|
|
% The live variable set before the first program point is ALWAYS
|
|
% Inputs.
|
|
%
|
|
live_variable_analysis_exec_path([FirstProgPoint - Goal], Inputs, _Outputs,
|
|
ModuleInfo, ProcInfo, no, LVBeforeNext, !ProcLVBefore,
|
|
!ProcLVAfter, !ProcVoidVar) :-
|
|
( if map.search(!.ProcLVBefore, FirstProgPoint, _LVBeforeFirst) then
|
|
true
|
|
else
|
|
LVBeforeFirst = set.list_to_set(Inputs),
|
|
map.set(FirstProgPoint, LVBeforeFirst, !ProcLVBefore)
|
|
),
|
|
|
|
% Live variable set after the first program point.
|
|
record_live_vars_at_prog_point(FirstProgPoint, LVBeforeNext, !ProcLVAfter),
|
|
|
|
% Collect void vars after this program point.
|
|
compute_useds_produceds(ModuleInfo, Goal, _UsedSet, ProducedSet),
|
|
collect_void_vars(FirstProgPoint, ProducedSet, ProcInfo, !ProcVoidVar).
|
|
|
|
% This predicate analyses execution paths with only one program point.
|
|
% So it must be called in a context that matches that condition.
|
|
%
|
|
:- pred live_variable_analysis_singleton_exec_path(execution_path::in,
|
|
list(prog_var)::in, list(prog_var)::in, module_info::in, proc_info::in,
|
|
pp_varset_table::in, pp_varset_table::out, pp_varset_table::in,
|
|
pp_varset_table::out, pp_varset_table::in, pp_varset_table::out) is det.
|
|
|
|
live_variable_analysis_singleton_exec_path([ProgPoint - Goal | _], Inputs,
|
|
Outputs, ModuleInfo, ProcInfo, !ProcLVBefore, !ProcLVAfter,
|
|
!ProcVoidVar) :-
|
|
LVBefore = set.list_to_set(Inputs),
|
|
map.set(ProgPoint, LVBefore, !ProcLVBefore),
|
|
LVAfter = set.list_to_set(Outputs),
|
|
map.set(ProgPoint, LVAfter, !ProcLVAfter),
|
|
|
|
% Collect void vars after this program point.
|
|
compute_useds_produceds(ModuleInfo, Goal, _UsedSet, ProducedSet),
|
|
collect_void_vars(ProgPoint, ProducedSet, ProcInfo, !ProcVoidVar).
|
|
live_variable_analysis_singleton_exec_path([], _, _, _, _,
|
|
!ProcLVBefore, !ProcLVAfter, !ProcVoidVar) :-
|
|
unexpected($pred, "empty list").
|
|
|
|
% A variable is live at a program point if it is live in one of
|
|
% the execution paths that covers the program point.
|
|
% Therefore we need to union the existing live variable set at a program
|
|
% point with the newly found.
|
|
%
|
|
:- pred record_live_vars_at_prog_point(program_point::in, variable_set::in,
|
|
pp_varset_table::in, pp_varset_table::out) is det.
|
|
|
|
record_live_vars_at_prog_point(ProgPoint, LV, !ProcLV) :-
|
|
( if map.search(!.ProcLV, ProgPoint, ExistingLV) then
|
|
map.set(ProgPoint, set.union(ExistingLV, LV), !ProcLV)
|
|
else
|
|
map.set(ProgPoint, LV, !ProcLV)
|
|
).
|
|
|
|
% Compute used and produced variables in an atomic goal, which
|
|
% has been recorded alongside a program point in an execution_path.
|
|
% A variable is used in an atomic goal if it is input to the goal.
|
|
% It is produced in the atomic goal if it is output of the goal.
|
|
%
|
|
:- pred compute_useds_produceds(module_info::in, hlds_goal::in,
|
|
variable_set::out, variable_set::out) is det.
|
|
|
|
compute_useds_produceds(ModuleInfo, Goal, UsedSet, ProducedSet) :-
|
|
( if
|
|
% a removed switch
|
|
Goal = hlds_goal(switch(Var, _, _), _SwitchInfo)
|
|
then
|
|
Useds = [Var],
|
|
Produceds = []
|
|
else
|
|
Goal = hlds_goal(Expr, _Info),
|
|
( if
|
|
Expr = plain_call(CalleePredId, CalleeProcId, Args,
|
|
_BuiltIn, _Context, _Name)
|
|
then
|
|
get_inputs_outputs_proc_call(Args,
|
|
proc(CalleePredId, CalleeProcId), ModuleInfo,
|
|
Useds, Produceds)
|
|
else if
|
|
Expr = unify(_, _, _, Unification, _)
|
|
then
|
|
get_inputs_outputs_unification(Unification, Useds,
|
|
Produceds)
|
|
else if
|
|
( Expr = conj(_, [])
|
|
; Expr = disj([])
|
|
)
|
|
then
|
|
Useds = [],
|
|
Produceds = []
|
|
else
|
|
unexpected($pred,
|
|
"the expression must be either call, unify, true, or fail")
|
|
)
|
|
),
|
|
set.list_to_set(Useds, UsedSet),
|
|
set.list_to_set(Produceds, ProducedSet).
|
|
|
|
% Divide the variables appearing in a unification into lists of input
|
|
% variables and output variables.
|
|
%
|
|
:- pred get_inputs_outputs_unification(unification::in,
|
|
list(prog_var)::out, list(prog_var)::out) is det.
|
|
|
|
get_inputs_outputs_unification(construct(LVar, _, Args, _, _, _, _),
|
|
Args, [LVar]).
|
|
get_inputs_outputs_unification(deconstruct(LVar, _, Args, _, _, _),
|
|
[LVar], Args).
|
|
get_inputs_outputs_unification(assign(LVar, RVar), [RVar], [LVar]).
|
|
get_inputs_outputs_unification(simple_test(LVar, RVar), [LVar, RVar], []).
|
|
get_inputs_outputs_unification(complicated_unify(_, _, _), [], []).
|
|
|
|
% Divide the arguments in a procedure call into lists of input
|
|
% variables and output variables.
|
|
%
|
|
:- pred get_inputs_outputs_proc_call(list(prog_var)::in, pred_proc_id::in,
|
|
module_info::in, list(prog_var)::out, list(prog_var)::out) is det.
|
|
|
|
get_inputs_outputs_proc_call(ActualArgs, CalleeId, ModuleInfo,
|
|
ActualInputs, ActualOutputs) :-
|
|
module_info_pred_proc_info(ModuleInfo, CalleeId, _PredInfo, CalleeInfo),
|
|
find_input_output_args(ModuleInfo, CalleeInfo, Inputs, Outputs),
|
|
|
|
proc_info_get_headvars(CalleeInfo, FormalArgs),
|
|
get_inputs_outputs_proc_call_2(FormalArgs, ActualArgs,
|
|
Inputs, Outputs, [], ActualInputs, [], ActualOutputs).
|
|
|
|
:- pred get_inputs_outputs_proc_call_2(list(prog_var)::in,
|
|
list(prog_var)::in, list(prog_var)::in, list(prog_var)::in,
|
|
list(prog_var)::in, list(prog_var)::out, list(prog_var)::in,
|
|
list(prog_var)::out) is det.
|
|
|
|
get_inputs_outputs_proc_call_2([], [], _, _, !ActualInputs, !ActualOutputs).
|
|
get_inputs_outputs_proc_call_2([], [_ | _], _, _, !ActualInputs,
|
|
!ActualOutputs) :-
|
|
unexpected($pred, "mismatched lists").
|
|
get_inputs_outputs_proc_call_2([_ | _], [], _, _, !ActualInputs,
|
|
!ActualOutputs) :-
|
|
unexpected($pred, "mismatched lists").
|
|
get_inputs_outputs_proc_call_2([FormalArg | FormalArgs],
|
|
[ActualArg | ActualArgs], Inputs, Outputs, !ActualInputs,
|
|
!ActualOutputs) :-
|
|
( if list.member(FormalArg, Inputs) then
|
|
% This formal argument is an input, so the correspondig argument
|
|
% is an actual input argument.
|
|
ActualInputs1 = [ActualArg | !.ActualInputs],
|
|
ActualOutputs1 = !.ActualOutputs
|
|
else if list.member(FormalArg, Outputs) then
|
|
% This formal argument is an output, so the corresponding argument
|
|
% is an actual output argument.
|
|
ActualOutputs1 = [ActualArg | !.ActualOutputs],
|
|
ActualInputs1 = !.ActualInputs
|
|
else
|
|
% This formal param is neither an output nor an input, so ignore
|
|
% the corresponding arg.
|
|
ActualInputs1 = !.ActualInputs,
|
|
ActualOutputs1 = !.ActualOutputs
|
|
),
|
|
get_inputs_outputs_proc_call_2(FormalArgs, ActualArgs, Inputs, Outputs,
|
|
ActualInputs1, !:ActualInputs, ActualOutputs1, !:ActualOutputs).
|
|
|
|
% Collect variables whose names start with _, i.e., void variables.
|
|
% I am considering those variables dead right after created in the live
|
|
% variable and region analyses.
|
|
%
|
|
:- pred collect_void_vars(program_point::in, variable_set::in, proc_info::in,
|
|
pp_varset_table::in, pp_varset_table::out) is det.
|
|
|
|
collect_void_vars(ProgPoint, ProducedSet, ProcInfo, !ProcVoidVar) :-
|
|
( if map.search(!.ProcVoidVar, ProgPoint, _DeadVars) then
|
|
true
|
|
else
|
|
proc_info_get_var_table(ProcInfo, VarTable),
|
|
set.fold(void_var(VarTable), ProducedSet, set.init, VoidVars),
|
|
map.set(ProgPoint, VoidVars, !ProcVoidVar)
|
|
).
|
|
|
|
% To be used with the fold above: if Var is a void variable,
|
|
% add it to VoidVars set.
|
|
%
|
|
:- pred void_var(var_table::in, prog_var::in,
|
|
variable_set::in, variable_set::out) is det.
|
|
|
|
void_var(VarTable, Var, !VoidVars) :-
|
|
lookup_var_entry(VarTable, Var, VarEntry),
|
|
( if string.index(VarEntry ^ vte_name, 0, '_') then
|
|
set.insert(Var, !VoidVars)
|
|
else
|
|
true
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module transform_hlds.rbmm.live_variable_analysis.
|
|
%---------------------------------------------------------------------------%
|