mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-16 09:53:36 +00:00
This fixes the performance problem reported in Mantis bug #562. compiler/hlds_pred.m: Instead of storing a varset and a vartypes in each proc_info, store just a var_table. Update the predicates that create or clone procedures accordingly. Where we had operations on proc_infos that had two versions, one operating on a varset/vartypes pair and one operating on var_table, keep only the latter, with the (shorter) name of the former. Delete the arity argument of proc_info_init, because the only valid value of that argument is the length of the list of the argument types. (In other words, this arg has been redundant all along.) Change the operations that create new variables in a procedure to get the caller to specify the (base) name of the new variable up front. Delete the unused predicate proc_info_ensure_unique_names. compiler/type_util.m: Due to the change above, we now construct var_tables during the construction of the HLDS. The code that does that needs to fill in the field that says whether the type of each variable in the table is a dummy type or not. However, at this time, the pass that decides type representations has not been run yet. The code of is_type_a_dummy used to throw an exception in such situations. Change this so that in such situations, is_type_a_dummy returns a placeholder, not-guaranteed-to-be-correct value. Document why this is ok. compiler/post_typecheck.m: Replace the placeholder values in vte_is_dummy fields in all the entries in the var_tables in all (valid) predicates with valid data. (If there are any invalid predicates, the compilation will fail anyway.) The clause_to_proc pass will copy these updated var_tables to be the initial var_tables in procedures. compiler/make_goal.m: Change the operations that create new variables in a procedure to get the caller to specify the (base) name of the new variable up front. This is simpler than the old method, which created new variables without a name, and had the caller give them a name as a separate operation. And since var_tables need this info, get the caller to also specify whether the type is a dummy, if the type is not a builtin type which is known not to be a dummy. compiler/var_table.m: Document the times when the types and is_dummy fields in var_table entries become meaningful. Fix a potential bug: when performing type substitutions in var_table entries, updating a variable's type may change whether that variable is a dummy or not, so recompute that info. It is quite possible that we *never* replace a nondummy type with a dummy type or vice versa, but in the absence of a convincing correctness argument for that proposition, better safe than sorry. Export the previously-private predicate transform_var_table to post_typecheck. Add code to implement the unused predicate deleted from hlds_pred.m: at the time I wrote it, I haven't yet realised that it was unused. The code I wrote here is therefore unused as well, so it is commented out. I did not delete it, because it may be useful later on. compiler/direct_arg_in_out.m: Don't make and split var_tables, since it is no longer needed. compiler/accumulator.m: compiler/add_class.m: compiler/add_clause.m: compiler/add_heap_ops.m: compiler/add_pred.m: compiler/add_special_pred.m: compiler/add_trail_ops.m: compiler/arg_info.m: compiler/build_mode_constraints.m: compiler/bytecode_gen.m: compiler/check_typeclass.m: compiler/clause_to_proc.m: compiler/closure_analysis.m: compiler/code_gen.m: compiler/code_loc_dep.m: compiler/complexity.m: compiler/continuation_info.m: compiler/cse_detection.m: compiler/ctgc.livedata.m: compiler/deep_profiling.m: compiler/default_func_mode.m: compiler/deforest.m: compiler/delay_construct.m: compiler/delay_partial_inst.m: compiler/dep_par_conj.m: compiler/det_analysis.m: compiler/det_report.m: compiler/distance_granularity.m: compiler/equiv_type_hlds.m: compiler/exception_analysis.m: compiler/float_regs.m: compiler/follow_code.m: compiler/goal_mode.m: compiler/goal_path.m: compiler/higher_order.m: compiler/hlds_out_pred.m: compiler/hlds_rtti.m: compiler/hlds_statistics.m: compiler/inlining.m: compiler/intermod.m: compiler/intermod_analysis.m: compiler/introduce_exists_casts.m: compiler/introduce_parallelism.m: compiler/lambda.m: compiler/lco.m: compiler/live_vars.m: compiler/liveness.m: compiler/loop_inv.m: compiler/mark_tail_calls.m: compiler/ml_accurate_gc.m: compiler/ml_args_util.m: compiler/ml_closure_gen.m: compiler/ml_gen_info.m: compiler/ml_proc_gen.m: compiler/mode_errors.m: compiler/mode_info.m: compiler/modecheck_goal.m: compiler/par_loop_control.m: compiler/pd_debug.m: compiler/pd_info.m: compiler/pd_util.m: compiler/polymorphism_info.m: compiler/post_typecheck.m: compiler/proc_gen.m: compiler/proc_requests.m: compiler/purity.m: compiler/push_goals_together.m: compiler/quantification.m: compiler/rbmm.add_rbmm_goal_infos.m: compiler/rbmm.live_variable_analysis.m: compiler/rbmm.points_to_analysis.m: compiler/rbmm.points_to_graph.m: compiler/rbmm.points_to_info.m: compiler/rbmm.region_liveness_info.m: compiler/rbmm.region_transformation.m: compiler/recompute_instmap_deltas.m: compiler/saved_vars.m: compiler/simplify_goal_unify.m: compiler/simplify_info.m: compiler/simplify_proc.m: compiler/size_prof.m: compiler/ssdebug.m: compiler/stack_alloc.m: compiler/stack_layout.m: compiler/stack_opt.m: compiler/stm_expand.m: compiler/store_alloc.m: compiler/structure_reuse.analysis.m: compiler/structure_reuse.direct.choose_reuse.m: compiler/structure_reuse.direct.detect_garbage.m: compiler/structure_reuse.domain.m: compiler/structure_reuse.indirect.m: compiler/structure_reuse.lbu.m: compiler/structure_reuse.lfu.m: compiler/structure_reuse.versions.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_build.m: compiler/term_constr_initial.m: compiler/term_errors.m: compiler/term_pass1.m: compiler/term_pass2.m: compiler/trace_gen.m: compiler/trailing_analysis.m: compiler/try_expand.m: compiler/tupling.m: compiler/unneeded_code.m: compiler/untupling.m: compiler/unused_args.m: compiler/unused_imports.m: Conform to the changes above. Mostly this means - not passing a module_info to get a var_table out of a proc_info, but - having to pass a module_info to code that either constructs a var_table, or adds entries to a var_table (since we now need the type table to figure out whether variables' types are dummies).
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_valid_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.
|
|
%---------------------------------------------------------------------------%
|