[m-rev.] For review: (re-send with the diff inlined) adding region-based memory management (RBMM) analysis
Julien Fischer
juliensf at csse.unimelb.edu.au
Tue May 15 19:03:43 AEST 2007
Hi Quan,
Some initial comments ...
On Tue, 15 May 2007, Quan Phan wrote:
> Estimated hours taken: 50 (for integrating into MMC 0.13.x).
That seems to have changed since the last version you posted :-)
(Hopefully the diff is *not* for 0.13 though.)
>
> The analysis divides the heap used by a program into regions and reasons
> about their lifetime, based on those data it then detects the points
> where instructions for creating and destroying regions can be added.
> Currently it just gathers the information and generates region-annotated
> Mercury code that can be used for simulation purpose. The analysis works
> for single-module programs only.
>
> compiler/smm_data.m
> compiler/smm_utils.m
> Data and procedures that are used in RBMM as well as CTGC
>
> compiler/rbmm_utils.m
>
> compiler/rpta_info.m
> compiler/rpt_graph.m
> compiler/rpt_alpha_mapping.m
> Define data types used in region points-to analysis.
>
> compiler/rpta_fixpoint_table.m
> Fixpoint computation for region points-to analysis.
> compiler/rpta_run.m
> Implementation of the region points-to analysis.
Has it been decided which package the RBMM stuff is being put in
yet?
> compiler/lra_data.m
> Define data types used in live region analysis.
>
> compiler/lra_lva.m
> compiler/lra_rules.m
> Implementation of the live region analysis
>
> compiler/region_transform.m
> Introducing region instructions.
>
> compiler/pp_region_annotated_code.m
> Generate region annotated code for simulating purpose.
> The above are new files.
>
> compiler/fixpoint_table.m
> re-added but this file is not used before, to perform fixpoint
> computation.
Do not add this file, Nancy has already added it. It's in
ctgc.fixpoint.m.
> compiler/mercury_compile.m
> Add calls to the region analysis.
> compiler/options.m
> add option --region-analysis.
...
> Index: lra_data.m
> ===================================================================
> RCS file: lra_data.m
> diff -N lra_data.m
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ lra_data.m 15 May 2007 04:10:51 -0000
> @@ -0,0 +1,107 @@
> +%-----------------------------------------------------------------------------%
> +% vim: ft=mercury ts=4 sw=4 et
> +%-----------------------------------------------------------------------------%
> +% Copyright (C) 2005-2007 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 lra_data.m.
> +% main author: Quan Phan
> +%
> +% Defines the data structures used in the live region analysis.
> +
> +:- module lra_data.
> +
> +:- interface.
> +
> +:- import_module hlds.
> +:- import_module hlds.hlds_pred.
> +:- import_module hlds.hlds_goal.
> +
> +:- import_module parse_tree.
> +:- import_module parse_tree.prog_data.
> +
> +:- import_module rpt_graph.
> +:- import_module smm_data.
> +:- import_module list.
> +:- import_module assoc_list.
> +:- import_module set.
> +:- import_module map.
The compiler imports and the standard library imports should be in
two separate (sorted) groups. (See the `Module imports' section of
the coding standard.
> +:- type execution_path == assoc_list(smm_data.program_point, hlds_goal).
> +:- type ep_table == map(pred_proc_id, list(execution_path)).
I suggest `execution_path_table' instead of `ep_table'.
> +%----------------------------------------------------------------------------%
> +%
> +% part for program variables
> +%
> +
> + % to represent a set of program variables
Sentences in comments should begin with a capital letter and finish
with a full stop.
I would write that as:
Represents a set of program variables.
...
> + %
> +:- type variable_set == set(prog_var).
... however variable_set is not a very descriptive type name.
A more appropriate name would be along live_vars or something else
that conveys to the reader that this set of prog_vars is the set
of live prog_vars. (I haven't checked if that is always the case.)
> + % to represent the relation between a program point and a set of
> + % variables. E.g., a map of this type can be the sets of live
> + % variables before program points in a procedure.
> + %
> +:- type pp_varset_table == map(smm_data.program_point, variable_set).
What else is it used for aside from live variables?
> +
> + % to represent the relation between a procedure and sets of variables
> + % associated with its program points.
> + %
> +:- type proc_pp_varset_table == map(pred_proc_id, pp_varset_table).
> +
> +%----------------------------------------------------------------------------%
> +%
> +% part for region/node
> +%
This section defines region_sets, so a section heading along the lines
of Region sets would be more meaningful.
> + % represent a set of regions, e.g., deadR, bornR, ..., live regions
> before
> + % and after a program point.
> + %
> +:- type region_set == set(rptg_node).
> +
> +:- pred region_set_equal(region_set::in, region_set::in) is semidet.
> +
> + % to represent the relation between a procedure and its interesting
> sets
> + % of regions, such as deadR, bornR, constantR
> + %
> +:- type proc_region_set_table == map(pred_proc_id, region_set).
> +
> +:- pred proc_region_set_table_equal(proc_region_set_table::in,
> + proc_region_set_table::in) is semidet.
> +
> + % to represent the relation between a program point and its region set
> + % e.g., live regions before the pp, live regions after the pp
> + %
> +:- type pp_region_set_table == map(smm_data.program_point, region_set).
> +
> + % represent the relation between a procedure and sets of regions
> + % associated with its program points
> + %
> +:- type proc_pp_region_set_table == map(pred_proc_id, pp_region_set_table).
> +
> +:- implementation.
> +
> +region_set_equal(RegionSet1, RegionSet2) :-
> + set.equal(RegionSet1, RegionSet2).
> +
> +proc_region_set_table_equal(ProcRegionSetTable1, ProcRegionSetTable2)
> :-
> + map.count(ProcRegionSetTable1, C1),
> + map.count(ProcRegionSetTable2, C2),
> + C1 = C2,
> +
> + map.keys(ProcRegionSetTable1, PredProcIds1),
> + prst_equal_2(PredProcIds1, ProcRegionSetTable1, ProcRegionSetTable2).
This doesn't look right. It will succeed if the key set of
ProcRegionSetTable1 is a strict subset of the key set of ProcRegionSetTable2.
(and the associate regions sets are equal)
Is that what you mean to happen here?
> +:- pred prst_equal_2(list(pred_proc_id)::in, proc_region_set_table::in,
> + proc_region_set_table::in) is semidet.
> +
> +prst_equal_2([], _, _).
> +prst_equal_2([Pid|Pids], PRST1, PRST2) :-
The usual abbreviation for variables of type pred_proc_id is PPId.
You should use that here, e.g. [ PPId | PPIds ].
> + map.search(PRST2, Pid, RS2),
> +
> + map.lookup(PRST1, Pid, RS1),
> + set.equal(RS1, RS2),
> + prst_equal_2(Pids, PRST1, PRST2).
...
> Index: lra_lva.m
> ===================================================================
> RCS file: lra_lva.m
> diff -N lra_lva.m
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ lra_lva.m 15 May 2007 04:13:52 -0000
> @@ -0,0 +1,1002 @@
> +%-----------------------------------------------------------------------------%
> +% vim: ft=mercury ts=4 sw=4 et
> +%-----------------------------------------------------------------------------%
> +% Copyright (C) 2005-2007 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 lra_lva.m.
> +% Main author: Quan Phan.
> +%
> +% This module implements the live region analysis as described in the
> +% technical report. It is composed of:
Where is the technical report available? Include that information in this
comment.
> +% 1. collecting all execution paths (EP) of procedures,
> +% 2. based on those EPs collecting live variables at each program point,
> +% 3. based on those EPs with live variables collecting live regions at
> +% each program point.
> +% 4. updating the initial bornR and deadR, then computing constantR for
> each
> +% procedure.
> +
> +:- module lra_lva.
> +
> +:- interface.
> +
> +:- import_module hlds.
> +:- import_module hlds.hlds_module.
> +
> +:- import_module io.
> +
> +:- import_module rpta_info.
> +:- import_module lra_data.
> +
> + % this collects EPs for each procedure.
> + %
> +:- pred execution_path_analysis(module_info::in, ep_table::out, io::di,
> + io::uo) is det.
A lot of this code seems to have the I/O state threaded through it
uncessarily, i.e. the code through which it is threaded doesn't actually
perform any I/O.
> + % this collects live variable sets.
> + %
> +:- pred live_variable_analysis(module_info::in, ep_table::in,
> + proc_pp_varset_table::out, proc_pp_varset_table::out,
> + proc_pp_varset_table::out, io::di, io::uo) is det.
> +
> + % this collects live region sets.
> + %
> +:- pred live_region_analysis(module_info::in, rpta_info_table::in,
> + proc_pp_varset_table::in, proc_pp_varset_table::in,
> + proc_pp_varset_table::in, proc_pp_region_set_table::out,
> + proc_pp_region_set_table::out, proc_pp_region_set_table::out,
> + proc_region_set_table::out, proc_region_set_table::out,
> + proc_region_set_table::out, proc_region_set_table::out,
> + proc_region_set_table::out, io::di, io::uo) is det.
> +
> + % this predicate reasons about lifetime of regions across procedure
> + % boundary. It will update the initial deadR and bornR sets and compute
> + % constantR set.
> + %
> +:- pred compute_interproc_region_lifetime(module_info::in,
> + rpta_info_table::in, ep_table::in, proc_pp_region_set_table::in,
> + proc_pp_region_set_table::in, proc_region_set_table::in,
> + proc_region_set_table::in, proc_region_set_table::out,
> + proc_region_set_table::in, proc_region_set_table::out,
> + proc_region_set_table::in, proc_region_set_table::out,
> + io::di, io::uo) is det.
> +
> + % this predicate removes regions of primitive types from the input
> data
> + % structures.
> + % The reason for this is the assumption that primitive values are not
> + % boxed (i.e., not store in regions).
> + %
> +:- pred ignore_primitive_regions(module_info::in, rpta_info_table::in,
> + proc_region_set_table::in, proc_region_set_table::out,
> + proc_region_set_table::in, proc_region_set_table::out,
> + proc_region_set_table::in, proc_region_set_table::out,
> + proc_region_set_table::in, proc_region_set_table::out,
> + proc_pp_region_set_table::in, proc_pp_region_set_table::out,
> + proc_pp_region_set_table::in, proc_pp_region_set_table::out,
> + proc_pp_region_set_table::in, proc_pp_region_set_table::out) is det.
> +%-----------------------------------------------------------------------------%
> +
> +:- implementation.
> +
> +:- import_module hlds.hlds_pred.
> +:- import_module hlds.hlds_goal.
> +:- import_module hlds.arg_info.
> +
> +:- import_module parse_tree.
> +:- import_module parse_tree.prog_data.
> +:- import_module parse_tree.mercury_to_mercury.
> +:- import_module check_hlds.
> +:- import_module check_hlds.goal_path.
> +:- import_module check_hlds.type_util.
> +:- import_module libs.
> +:- import_module libs.compiler_util.
> +:- import_module smm_data.
> +:- import_module smm_utils.
> +:- import_module rpt_graph.
> +:- import_module lra_rules.
> +
> +:- import_module bool.
> +:- import_module varset.
> +:- import_module map.
> +:- import_module list.
> +:- import_module assoc_list.
> +:- import_module set.
> +:- import_module string.
> +:- import_module term.
> +:- import_module pair.
> +:- import_module svmap.
> +:- import_module svset.
See the above comments regarding the formatting of blocks of import_module
declarations.
...
> +
> +% part for execution path analysis
> +%
I suggest just:
Execution path analysis
> +
> +execution_path_analysis(HLDS, EPTable, !IO) :-
I suggest ExecPathTable, rather than EPTable.
I suggest s/HLDS/ModuleInfo/ above since that is the convention used
throughout the rest of the compiler (exception mercury_compile.m.).
> + module_info_predids(PredIds, HLDS, _),
> + map.init(EPTable0),
> + list.foldl2(execution_path_analysis_pred(HLDS), PredIds, EPTable0,
> + EPTable, !IO).
> +
> +:- pred execution_path_analysis_pred(module_info::in, pred_id::in,
> + ep_table::in, ep_table::out, io::di, io::uo) is det.
> +
> +execution_path_analysis_pred(HLDS, PredId, !EPTable, !IO) :-
> + module_info_pred_info(HLDS, PredId, PredInfo),
> + pred_info_non_imported_procids(PredInfo) = ProcIds,
> + list.foldl2(execution_path_analysis_proc(HLDS, PredId), ProcIds,
> + !EPTable, !IO).
> +
> +:- pred execution_path_analysis_proc(module_info::in, pred_id::in,
> + proc_id::in, ep_table::in, ep_table::out, io::di, io::uo) is det.
> +
> +execution_path_analysis_proc(HLDS, PredId, ProcId, EPTable0, EPTable,
> !IO) :-
> + PredProcId = proc(PredId, ProcId),
> + ( if
> + smm_utils.some_are_special_preds([PredProcId], HLDS)
> + then
> + EPTable = EPTable0
> + else
> + module_info_pred_proc_info(HLDS, PredProcId, _PredInfo, ProcInfo),
Call module_info_proc_info/3 instead of module_info_pred_proc_info/4 here.
> + execution_paths(ProcInfo, HLDS, EPs),
> +
> + map.set(EPTable0, PredProcId, EPs, EPTable)
> + ).
Use state variables for EPTable in the above predicate.
> +
> +:- pred execution_paths(proc_info::in, module_info::in,
> + list(execution_path)::out) is det.
I suggest renaming this to something like compute_execution_paths
or construct_execution_paths.
> +execution_paths(ProcInfo, HLDS, EPs) :-
> + % to fill the goals with program point information
> + fill_goal_path_slots(HLDS, ProcInfo, ProcInfo1),
> +
> + proc_info_get_goal(ProcInfo1, Goal),
> + execution_paths_covered_goal(ProcInfo, Goal, [[]], EPs).
> +
> + % construct execution paths that cover (are up to and include) this goal.
> + %
> +:- pred execution_paths_covered_goal(proc_info::in, hlds_goal::in,
> + list(execution_path)::in, list(execution_path)::out) is det.
> +
> +execution_paths_covered_goal(ProcInfo, Goal, EPsUntilGoal,
> EPsCoveredGoal) :-
> + Goal = hlds_goal(Expr, Info),
> + (
> + goal_is_atomic(Expr)
> + ->
> + (
> + (
> + Expr = unify(_, _, _, _, _)
> + ;
> + Expr = plain_call(_, _, _, _, _, _)
> + ;
> + Expr = conj(_ConjType, [])
> + ;
> + Expr = disj([])
> + )
> + ->
> + % retrieve the program point of this goal
> + program_point_init(Info, PP),
> + append_to_each_ep(EPsUntilGoal, [[pair(PP, Goal)]], EPsCoveredGoal)
> + ;
> + % XXX: other kinds of atomic calls (generic_call,
> + % foreign_proc), TEMPORARILY ignored their corresponding pps.
> + append_to_each_ep(EPsUntilGoal, [[]], EPsCoveredGoal)
> + )
> + ;
> + execution_paths_covered_compound_goal(ProcInfo, Goal,
> + EPsUntilGoal, EPsCoveredGoal)
> + ).
> +
> + % extend current eps to cover this compound goal.
> + %
> +:- pred execution_paths_covered_compound_goal(proc_info::in,
> hlds_goal::in,
> + list(execution_path)::in, list(execution_path)::out) is det.
> +
> +execution_paths_covered_compound_goal(ProcInfo, CompoundGoal,
> EPsBeforeGoal,
> + EPsCoveredGoal) :-
> + CompoundGoal = hlds_goal(Expr, _Info),
> + (
> + Expr = conj(_ConjType, Goals)
> + ->
> + execution_paths_covered_conj(ProcInfo, Goals,
> + EPsBeforeGoal, EPsCoveredGoal)
> + ;
> + Expr = switch(_A, _B, Cases)
> + ->
> + execution_paths_covered_cases(ProcInfo, CompoundGoal, Cases,
> + EPsBeforeGoal, EPsCoveredGoal)
> + ;
> + Expr = disj(Goals)
> + ->
> + execution_paths_covered_disj(ProcInfo, Goals,
> + EPsBeforeGoal, EPsCoveredGoal)
> + ;
> + Expr = negation(Goal)
> + ->
> + execution_paths_covered_goal(ProcInfo, Goal,
> + EPsBeforeGoal, EPsCoveredGoal)
> + ;
> + Expr = scope(_ScopeReason, Goal)
> + ->
> + execution_paths_covered_goal(ProcInfo, Goal,
> + EPsBeforeGoal, EPsCoveredGoal)
> + ;
> + Expr = if_then_else(_V, Cond, Then, Else)
> + ->
> + execution_paths_covered_goal(ProcInfo, Cond,
> + EPsBeforeGoal, EPsCoveredCond),
> + execution_paths_covered_goal(ProcInfo, Then,
> + EPsCoveredCond, EPsCoveredThen),
> + execution_paths_covered_goal(ProcInfo, Else,
> + EPsBeforeGoal, EPsCoveredElse),
> + % In the operational semantics of Mercury (MMC),
Delete `(MMC)'.
> + % if g1 then g2 else g3 is equivalent to
> + % ((g1,g2);(g3))
> + %
> + list.append(EPsCoveredThen, EPsCoveredElse, EPsCoveredGoal)
> + ;
> + unexpected(thisfile, "collect_execution_path_in_compound_goal: "
> + ++ "found atomic call")
> + ).
Rewrite the above predicate to use a switch and abort if you find any atomic
goals.
> +
> + % the idea is to extend all the current execution paths with all the
> goals
> + % in this conjunction.
> + %
> +:- pred execution_paths_covered_conj(proc_info::in, list(hlds_goal)::in,
> + list(execution_path)::in, list(execution_path)::out) is det.
> +
> +execution_paths_covered_conj(_ProcInfo, [], EPsBeforeGoal, EPsBeforeGoal).
> +execution_paths_covered_conj(ProcInfo, [Goal|Others],
> + EPsBeforeGoal, EPsCoveredGoal) :-
> + % extend all current EPs to this Goal
> + execution_paths_covered_goal(ProcInfo, Goal, EPsBeforeGoal,
> + EPsCoveredThisGoal),
> +
> + % extend them with to the other goals
> + execution_paths_covered_conj(ProcInfo, Others, EPsCoveredThisGoal,
> + EPsCoveredGoal).
> +
> + % the idea is to extend all the current ep with each branch of this
> + % disjunction.
> + % E.g. if before this disj we have 2 eps, this disj has 3 branches,
> + % then after this extension we will have 6 eps: 2 extended to the 1st
> + % branch, 2 to the 2nd, 2 to the 3rd.
> + %
> +:- pred execution_paths_covered_disj(proc_info::in, list(hlds_goal)::in,
> + list(execution_path)::in, list(execution_path)::out) is det.
> +
> +execution_paths_covered_disj(_ProcInfo, [], _EPsBeforeGoal, []).
> +execution_paths_covered_disj(ProcInfo, [Goal|Others], EPsBeforeGoal,
Rather than, [Goal|Others], I suggest [Disj | Disjs].
> + EPsCoveredGoal) :-
> + % extend all current EPs to this goal
> + execution_paths_covered_goal(ProcInfo, Goal, EPsBeforeGoal,
> + EPsCoveredThisGoal),
> +
> + % extend all current EPs to each of the other goals (branches)
> + execution_paths_covered_disj(ProcInfo, Others, EPsBeforeGoal,
> + EPsCoveredOtherGoals),
> +
> + % they are all EPs that cover this disjunction
> + list.append(EPsCoveredThisGoal, EPsCoveredOtherGoals, EPsCoveredGoal).
> +
> + % the next pp, if any, will be a first-shared-point.
> + % This is for the situation where MMC detects a disj is actually a
> + % switch (semidet or det disj).
> + % One noticeable issue here is that MMC removes the unification of the
> + % switched-on variable with a constant and/or a functor of arity 0
> (f/0).
> + % Those removals cause eps to have fewer pps than we want. The
> solution
> + % here is to add an invented program point for the removed
> unification.
> + % The corresponding goal of the pp is the switch goal itself so
> that we
> + % can get information about the switched-on variable in live variable
> + % analysis.
> + % Other than the above point, the algorithm is the same as a normal disj.
> + %
> +:- pred execution_paths_covered_cases(proc_info::in, hlds_goal::in,
> + list(case)::in, list(execution_path)::in, list(execution_path)::out)
> + is det.
> +
> +execution_paths_covered_cases(_ProcInfo, _Switch, [], _EPsBeforeGoal, []).
> +execution_paths_covered_cases(ProcInfo, Switch, [Case|Others],
Likewise, use [Case | Cases] here.
> + EPsBeforeGoal, EPsCoveredGoal) :-
> + % deal with the removed unification, if any, and we add a dummy
> program
> + % point for the removed one because the MMC removes it
> + Case = case(ConsId, Goal),
> + Switch = hlds_goal(_SwitchExpr, Info),
> + smm_data.program_point_init(Info, PP),
> +
> + (
> + ConsId = cons(_SymName, Arity)
> + ->
> + ( if
> + Arity = 0
> + then
> + append_to_each_ep(EPsBeforeGoal, [[pair(PP, Switch)]],
> + EPsBeforeGoal1)
> + else
> + EPsBeforeGoal1 = EPsBeforeGoal
> + )
> + ;
> + ConsId = int_const(_Int)
> + ->
> + % need to add a dummy pp
> + append_to_each_ep(EPsBeforeGoal, [[pair(PP, Switch)]], EPsBeforeGoal1)
> + ;
> + ConsId = string_const(_String)
> + ->
> + % need to add a pp
> + append_to_each_ep(EPsBeforeGoal, [[pair(PP, Switch)]], EPsBeforeGoal1)
> + ;
> + ConsId = float_const(_Float)
> + ->
> + % need to add a pp
> + append_to_each_ep(EPsBeforeGoal, [[pair(PP, Switch)]], EPsBeforeGoal1)
> + ;
> + unexpected(thisfile, "execution_paths_covered_cases: new cons_id "
> + ++ "encountered")
> + ),
> + % as disj
> + execution_paths_covered_goal(ProcInfo, Goal,
> + EPsBeforeGoal1, EPsCoveredThisGoal),
> + execution_paths_covered_cases(ProcInfo, Switch, Others,
> + EPsBeforeGoal, EPsCoveredOtherGoals),
> + list.append(EPsCoveredThisGoal, EPsCoveredOtherGoals, EPsCoveredGoal).
> +
> + % extend each execution path in the first list with each in the
> + % second list, all the extended execution paths are put in the
> third list
> + %
> +:- pred append_to_each_ep(list(execution_path)::in,
> list(execution_path)::in,
> + list(execution_path)::out) is det.
> +
> +append_to_each_ep([], _ToBeAppended, []).
> +append_to_each_ep([EP|Others], ToBeAppended, ExtendedEPList) :-
> + % collect all the extensions of this EP
> + extend_ep(ToBeAppended, EP, ExtendedEPs),
> +
> + % collect the extensions of the others
> + append_to_each_ep(Others, ToBeAppended, OtherExtendedEPs),
> +
> + % put them all in the result
> + list.append(ExtendedEPs, OtherExtendedEPs, ExtendedEPList).
> +
> + % extend the execution path with each in the list,
> + % all the extensions are returned.
> + %
> +:- pred extend_ep(list(execution_path)::in, execution_path::in,
> + list(execution_path)::out) is det.
I suggest renaming that predicate, extend_execution_path.
> +extend_ep([], _EP, []).
> +extend_ep([Extension|Others], EP, ExtendedEPs) :-
> + append(EP, Extension, ExtendedEP),
> + extend_ep(Others, EP, OtherExtendedEPs),
> + append([ExtendedEP], OtherExtendedEPs, ExtendedEPs).
> +
> +%----------------------------------------------------------------------------%
> +%
> +% part for live variable analysis
Live variable analysis
> +%
> +% This analysis computes, for each procedure, the sets of live variables
> +% before and after each of its program points.
I suggest rewording that as:
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(HLDS, EPTable, LVBeforeTable, LVAfterTable,
> + VoidVarTable, !IO) :-
> + module_info_predids(PredIds, HLDS, _HLDS),
> + map.init(LVBeforeTable0),
> + map.init(LVAfterTable0),
> + map.init(VoidVarTable0),
> + list.foldl4(live_variable_analysis_pred(HLDS, EPTable), PredIds,
> + LVBeforeTable0, LVBeforeTable, LVAfterTable0, LVAfterTable,
> + VoidVarTable0, VoidVarTable, !IO).
> +
> +:- pred live_variable_analysis_pred(module_info::in, ep_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,
> + io::di, io::uo) is det.
> +
> +live_variable_analysis_pred(HLDS, EPTable, PredId, !LVBeforeTable,
> + !LVAfterTable, !VoidVarTable, !IO) :-
> + module_info_pred_info(HLDS, PredId, PredInfo),
> + pred_info_non_imported_procids(PredInfo) = ProcIds,
> + list.foldl4(live_variable_analysis_proc(HLDS, EPTable, PredId),
> + ProcIds, !LVBeforeTable, !LVAfterTable, !VoidVarTable, !IO).
> +
> +:- pred live_variable_analysis_proc(module_info::in, ep_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, io::di, io::uo) is det.
> +
> +live_variable_analysis_proc(HLDS, EPTable, PredId, ProcId, !LVBeforeTable,
> + !LVAfterTable, !VoidVarTable, !IO) :-
> + PredProcId = proc(PredId, ProcId),
> + ( if
> + smm_utils.some_are_special_preds([PredProcId], HLDS)
> + then
> + true
> + else
> + module_info_pred_proc_info(HLDS, PredProcId, _PredInfo, ProcInfo),
> + find_input_output_params(HLDS, ProcInfo, Inputs, Outputs),
> + map.lookup(EPTable, PredProcId, EPs),
> + live_variable_analysis_eps(EPs, Inputs, Outputs, HLDS, ProcInfo,
> + map.init, ProcLVBefore, map.init, ProcLVAfter, map.init,
> + ProcVoidVar, !IO),
> +
> + map.set(!.LVBeforeTable, PredProcId, ProcLVBefore, !:LVBeforeTable),
> + map.set(!.LVAfterTable, PredProcId, ProcLVAfter, !:LVAfterTable),
> + map.set(!.VoidVarTable, PredProcId, ProcVoidVar, !:VoidVarTable)
Us svmap.set/4 in preference to map.set/4 there.
...
> +:- pred live_variable_analysis_eps(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,
> + io::di, io::uo) is det.
> +
> + % Live variable analysis is backward, so we reverse the execution path
> + % before starting
> + %
> +live_variable_analysis_eps([], _Inputs, _Outputs, _HLDS, _ProcInfo,
> + !ProcLVBefore, !ProcLVAfter, !ProcVoidVar, !IO).
> +live_variable_analysis_eps([EP0|OtherEPs], Inputs, Outputs, HLDS,
> ProcInfo,
> + !ProcLVBefore, !ProcLVAfter, !ProcVoidVar, !IO) :-
> + list.reverse(EP0, EP1),
> + ( if
> + list.length(EP1) = 1
> + then
> + % i.e. there's only 1 pp in this EP, so the last pp is also
> + % the first pp
> + live_variable_analysis_singleton_ep(EP1, Inputs, Outputs, HLDS,
> + ProcInfo, !ProcLVBefore, !ProcLVAfter, !ProcVoidVar, !IO)
> + else
> + % start with the last pp
> + live_variable_analysis_ep(EP1, Inputs, Outputs, HLDS, ProcInfo,
> + yes, set.init, !ProcLVBefore, !ProcLVAfter, !ProcVoidVar, !IO)
> + ),
> + live_variable_analysis_eps(OtherEPs, Inputs, Outputs, HLDS, ProcInfo,
> + !ProcLVBefore, !ProcLVAfter, !ProcVoidVar, !IO).
> +
> +:- pred live_variable_analysis_ep(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, io::di, io::uo) is det.
> +
> +live_variable_analysis_ep([], _Inputs, _Outputs, _HLDS, _ProcInfo,_Last,
> + _LVBeforeNext, !ProcLVBefore, !ProcLVAfter, !ProcVoidVar, !IO).
> + % process the last program point in an execution path
> + %
> +live_variable_analysis_ep([(PP - Goal)|OtherPPGoals], Inputs, Outputs,
> HLDS,
> + ProcInfo, yes, _LVBeforeNext, !ProcLVBefore, ProcLVAfter0,
> + ProcLVAfter, !ProcVoidVar, !IO) :-
> + % live variable after of the last pp is ALWAYS set of output variables
> + ( if
> + map.search(ProcLVAfter0, PP, LastAfter)
> + then
> + ProcLVAfter1 = ProcLVAfter0,
> + LVAfter = LastAfter
> + else
> + LVAfter = set.list_to_set(Outputs),
> + map.set(ProcLVAfter0, PP, LVAfter, ProcLVAfter1)
> + ),
> +
> + % live variable before this last pp
> + compute_useds_produceds(HLDS, Goal, UsedSet, ProducedSet),
> + set.union(set.difference(LVAfter, ProducedSet), UsedSet,
> LVBeforeInThisEP),
> + record_live_vars_at_pp(PP, LVBeforeInThisEP, !ProcLVBefore),
> +
> + % collect void variables after this pp
> + collect_void_vars(PP, ProducedSet, ProcInfo, !ProcVoidVar),
> +
> + % continue analysing this ep
> + live_variable_analysis_ep(OtherPPGoals, Inputs, Outputs, HLDS, ProcInfo,
> + no, LVBeforeInThisEP, !ProcLVBefore, ProcLVAfter1,
> + ProcLVAfter, !ProcVoidVar, !IO).
> +
> + % process a middle program point
> + %
> +live_variable_analysis_ep([(PP - Goal), Another|OtherPPGoals], Inputs,
> + Outputs, HLDS, ProcInfo, no, LVBeforeNext, !ProcLVBefore,
> !ProcLVAfter,
> + !ProcVoidVar, !IO) :-
> + % this pp's lv after is the union of this pp's lv after in the
> + % other eps
> + record_live_vars_at_pp(PP, LVBeforeNext, !ProcLVAfter),
> +
> + % lv before this pp
> + compute_useds_produceds(HLDS, Goal, UsedSet, ProducedSet),
> + set.union(set.difference(LVBeforeNext, ProducedSet), UsedSet,
> + LVBeforeInThisEP),
> + record_live_vars_at_pp(PP, LVBeforeInThisEP, !ProcLVBefore),
> +
> + % collect void variables after this pp
> + collect_void_vars(PP, ProducedSet, ProcInfo, !ProcVoidVar),
> +
> + live_variable_analysis_ep([Another|OtherPPGoals], Inputs, Outputs, HLDS,
> + ProcInfo, no, LVBeforeInThisEP, !ProcLVBefore, !ProcLVAfter,
> + !ProcVoidVar, !IO).
> +
> + % the first program point
> + %
> +live_variable_analysis_ep([PP - Goal], Inputs, _Outputs, HLDS,
> ProcInfo, no,
> + LVBeforeNext, ProcLVBefore0, ProcLVBefore, !ProcLVAfter, !ProcVoidVar,
> + !IO) :-
> + % lv before the first pp is ALWAYS inputs
> + ( if
> + map.search(ProcLVBefore0, PP, _FirstBefore)
> + then
> + ProcLVBefore = ProcLVBefore0
> + else
> + LVBefore = set.list_to_set(Inputs),
> + map.set(ProcLVBefore0, PP, LVBefore, ProcLVBefore)
> + ),
> +
> + % update lv after this first pp
> + record_live_vars_at_pp(PP, LVBeforeNext, !ProcLVAfter),
> +
> + % collect void vars after this pp
> + compute_useds_produceds(HLDS, Goal, _UsedSet, ProducedSet),
> + collect_void_vars(PP, ProducedSet, ProcInfo, !ProcVoidVar).
> +
> +:- pred live_variable_analysis_singleton_ep(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,
> + io::di, io::uo) is det.
> +live_variable_analysis_singleton_ep([PP - Goal|_Others], Inputs, Outputs,
> + HLDS, ProcInfo, !ProcLVBefore, !ProcLVAfter, !ProcVoidVar, !IO) :-
> + LVBefore = set.list_to_set(Inputs),
> + map.set(!.ProcLVBefore, PP, LVBefore, !:ProcLVBefore),
> + LVAfter = set.list_to_set(Outputs),
> + map.set(!.ProcLVAfter, PP, LVAfter, !:ProcLVAfter),
> +
> + % collect void vars after this pp
> + compute_useds_produceds(HLDS, Goal, _UsedSet, ProducedSet),
> + collect_void_vars(PP, ProducedSet, ProcInfo, !ProcVoidVar).
> +
> +live_variable_analysis_singleton_ep([], _Inputs, _Outputs, _HLDS,
> _ProcInfo,
> + !ProcLVBefore, !ProcLVAfter, !ProcVoidVar, !IO) :-
> + unexpected(thisfile, "live_variable_analysis_singleton_ep: impossible").
> +
> + % A live variable is live at a program point if it is live in one of
> + % the execution paths that cover it.
> + % Therefore for a program point we need to union the existing live
> + % variable set with the newly found.
> + %
> +:- pred record_live_vars_at_pp(program_point::in, variable_set::in,
> + pp_varset_table::in, pp_varset_table::out) is det.
> +record_live_vars_at_pp(PP, LV, ProcLV0, ProcLV) :-
> + ( if
> + map.search(ProcLV0, PP, ExistingLV)
> + then
> + map.set(ProcLV0, PP, set.union(ExistingLV, LV), ProcLV)
> + else
> + map.set(ProcLV0, PP, LV, ProcLV)
> + ).
Use state variables there.
...
> +%----------------------------------------------------------------------------%
> +%
> +% part for live region analysis
> +%
Live region analysis
> +% This analysis "converts" the variable-based result of live variable
> +% analysis into region-based information.
> +% It also computes the inputR, outputR, localR, and the initial bornR and
> +% deadR for a procedure.
> +%
> +
> +live_region_analysis(HLDS, RptaInfoTable, LVBeforeTable, LVAfterTable,
> + VoidVarTable, LRBeforeTable, LRAfterTable, VoidVarRegionTable,
> + InputRTable, OutputRTable, BornRTable, DeadRTable, LocalRTable, !IO) :-
> + module_info_predids(PredIds, HLDS, _),
> + map.init(LRBeforeTable0),
> + map.init(LRAfterTable0),
> + map.init(VoidVarRegionTable0),
> + map.init(InputRTable0),
> + map.init(OutputRTable0),
> + map.init(BornRTable0),
> + map.init(DeadRTable0),
> + map.init(LocalRTable0),
It would be worth defining a data structure to hold all these maps.
It will (probably) be more efficient and it will certainly be easier
to understand.
> + foldl9(live_region_analysis_pred(HLDS, RptaInfoTable, LVBeforeTable,
> + LVAfterTable, VoidVarTable),
> + PredIds,
> + LRBeforeTable0, LRBeforeTable,
> + LRAfterTable0, LRAfterTable,
> + VoidVarRegionTable0, VoidVarRegionTable,
> + InputRTable0, InputRTable,
> + OutputRTable0, OutputRTable,
> + BornRTable0, BornRTable,
> + DeadRTable0, DeadRTable,
> + LocalRTable0, LocalRTable, !IO).
> +
> +:- pred live_region_analysis_pred(module_info::in, rpta_info_table::in,
> + proc_pp_varset_table::in, proc_pp_varset_table::in,
> + proc_pp_varset_table::in, pred_id::in,
> + proc_pp_region_set_table::in, proc_pp_region_set_table::out,
> + proc_pp_region_set_table::in, proc_pp_region_set_table::out,
> + proc_pp_region_set_table::in, proc_pp_region_set_table::out,
> + proc_region_set_table::in, proc_region_set_table::out,
> + proc_region_set_table::in, proc_region_set_table::out,
> + proc_region_set_table::in, proc_region_set_table::out,
> + proc_region_set_table::in, proc_region_set_table::out,
> + proc_region_set_table::in, proc_region_set_table::out,
> + io::di, io::uo) is det.
> +live_region_analysis_pred(HLDS, RptaInfoTable, LVBeforeTable,
> LVAfterTable,
> + VoidVarTable, PredId,
> + !LRBeforeTable, !LRAfterTable, !VoidVarRegionTable, !InputRTable,
> + !OutputRTable, !BornRTable, !DeadRTable, !LocalRTable, !IO) :-
The formatting of the argument for that predicate is odd.
> + module_info_pred_info(HLDS, PredId, PredInfo),
> + % this statement eliminates quite a lot compiler-generated predicates
> + % (it returns an empty list for those predicates)
> + pred_info_non_imported_procids(PredInfo) = ProcIds,
> +
> + foldl9(live_region_analysis_proc(HLDS, RptaInfoTable, LVBeforeTable,
> + LVAfterTable, VoidVarTable, PredId), ProcIds,
> + !LRBeforeTable, !LRAfterTable, !VoidVarRegionTable, !InputRTable,
> + !OutputRTable, !BornRTable, !DeadRTable, !LocalRTable, !IO).
> +
> +:- pred live_region_analysis_proc(module_info::in, rpta_info_table::in,
> + proc_pp_varset_table::in, proc_pp_varset_table::in,
> + proc_pp_varset_table::in, pred_id::in, proc_id::in,
> + proc_pp_region_set_table::in, proc_pp_region_set_table::out,
> + proc_pp_region_set_table::in, proc_pp_region_set_table::out,
> + proc_pp_region_set_table::in, proc_pp_region_set_table::out,
> + proc_region_set_table::in, proc_region_set_table::out,
> + proc_region_set_table::in, proc_region_set_table::out,
> + proc_region_set_table::in, proc_region_set_table::out,
> + proc_region_set_table::in, proc_region_set_table::out,
> + proc_region_set_table::in, proc_region_set_table::out,
> + io::di, io::uo) is det.
> +
> +live_region_analysis_proc(HLDS, RptaInfoTable, LVBeforeTable,
> LVAfterTable,
> + VoidVarTable, PredId, ProcId,
> + !LRBeforeTable, !LRAfterTable, !VoidVarRegionTable, !InputRTable,
> + !OutputRTable, !BornRTable, !DeadRTable, !LocalRTable, !IO) :-
> + PredProcId = proc(PredId, ProcId),
> + ( if
> + smm_utils.some_are_special_preds([PredProcId], HLDS)
> + then
> + % XXX: This action seems to be overkilled, it never goes in this
> + % branch.
> + % XXX: for now just ignore these special predicates
> + % such as __Unify__ and others or non-defined-in-module ones
> + % for the later ones, they should have been analysed when their
> + % modules analysed and those tables of them will be integrated.
> + % But it is not the case at the moment.
> + %
> + true
> + else
> + module_info_pred_proc_info(HLDS, PredProcId, _PredInfo, ProcInfo),
> +
> + % the region points-to graph of this procedure
> + (
> + RptaInfo = rpta_info_table_search_rpta_info(PredProcId,
> + RptaInfoTable)
> + ->
> + RptaInfo = rpta_info(Graph, _ALpha),
> +
> + % compute region sets
> + find_input_output_params(HLDS, ProcInfo, Inputs, Outputs),
> + lv_to_lr(set.from_list(Inputs), Graph, HLDS, ProcInfo, InputR),
> + lv_to_lr(set.from_list(Outputs), Graph, HLDS, ProcInfo, OutputR),
> +
> + % set of input regions
> + map.set(!.InputRTable, PredProcId, InputR, !:InputRTable),
> +
> + % set of output regions
> + map.set(!.OutputRTable, PredProcId, OutputR, !:OutputRTable),
> +
> + % bornR
> + set.difference(OutputR, InputR, BornR),
> + map.set(!.BornRTable, PredProcId, BornR, !:BornRTable),
> +
> + % deadR
> + set.difference(InputR, OutputR, DeadR),
> + map.set(!.DeadRTable, PredProcId, DeadR, !:DeadRTable),
> +
> + % localR
> + rptg_get_nodes(Graph, Nodes),
> + set.difference(set.difference(set.from_list(Nodes), InputR),
> + OutputR, LocalR),
> + map.set(!.LocalRTable, PredProcId, LocalR, !:LocalRTable),
> +
> + map.lookup(LVBeforeTable, PredProcId, ProcLVBefore),
> + map.foldl(proc_lv_to_proc_lr(Graph, HLDS, ProcInfo),
> + ProcLVBefore, map.init, ProcLRBefore),
> + map.set(!.LRBeforeTable, PredProcId, ProcLRBefore,
> + !:LRBeforeTable),
> +
> + map.lookup(LVAfterTable, PredProcId, ProcLVAfter),
> + map.foldl(proc_lv_to_proc_lr(Graph, HLDS, ProcInfo),
> + ProcLVAfter, map.init, ProcLRAfter),
> + map.set(!.LRAfterTable, PredProcId, ProcLRAfter, !:LRAfterTable),
> +
> + map.lookup(VoidVarTable, PredProcId, ProcVoidVar),
> + map.foldl(proc_lv_to_proc_lr(Graph, HLDS, ProcInfo),
> + ProcVoidVar, map.init, ProcVoidVarRegion),
> + map.set(!.VoidVarRegionTable, PredProcId, ProcVoidVarRegion,
> + !:VoidVarRegionTable)
> + ;
> + unexpected(thisfile, "live_region_analysis_proc: rpta_info must"
> + ++ " exist")
> + )
> + ).
> +
> +:- pred proc_lv_to_proc_lr(rpt_graph::in, module_info::in, proc_info::in,
> + program_point::in, variable_set::in, pp_region_set_table::in,
> + pp_region_set_table::out) is det.
> +proc_lv_to_proc_lr(Graph, HLDS, ProcInfo, PP, LVs, !ProcLRMap) :-
> + lv_to_lr(LVs, Graph, HLDS, ProcInfo, LRs),
> + map.set(!.ProcLRMap, PP, LRs, !:ProcLRMap).
> +
> +:- pred foldl9(pred(L, A, A, B, B, C, C, D, D, E, E, F, F, G, G, H, H,
> I, I),
> + list(L),
> + A, A, B, B, C, C, D, D, E, E, F, F, G, G, H, H, I, I).
> +:- mode foldl9(pred(in, in, out, in, out, in, out, in, out, in, out,
> in, out,
> + in, out, in, out, di, uo) is det,
> + in, in, out, in, out, in, out, in, out, in, out, in, out, in, out, in,
> + out, di, uo) is det.
> +foldl9(_, [], !A, !B, !C, !D, !E, !F, !G, !H, !I).
> +foldl9(P, [H|T], !A, !B, !C, !D, !E, !F, !G, !H, !I) :-
> + call(P, H, !A, !B, !C, !D, !E, !F, !G, !H, !I),
> + foldl9(P, T, !A, !B, !C, !D, !E, !F, !G, !H, !I).
If you need that predicate then it should be added to the list module in
the standard library rather than defined here.
> +:- pred lv_to_lr(variable_set::in, rpt_graph::in, module_info::in,
> + proc_info::in, region_set::out) is det.
> +lv_to_lr(LVSet, Graph, HLDS, ProcInfo, LRSet) :-
> + (
> + set.empty(LVSet)
> + ->
> + set.init(LRSet)
> + ;
> + % collect reachable regions at this pp
> + set.init(LRSet0),
> + set.fold(reach_from_a_variable(Graph, HLDS, ProcInfo), LVSet,
> + LRSet0, LRSet)
> + ).
> +
> +:- pred find_input_output_params(module_info::in, proc_info::in,
> + list(prog_var)::out, list(prog_var)::out) is det.
> +find_input_output_params(HLDS, CalleeProcInfo, Inputs, Outputs) :-
> + proc_info_get_headvars(CalleeProcInfo, ArgVars),
> + proc_info_get_vartypes(CalleeProcInfo, VarTypes),
> + list.map(map.lookup(VarTypes), ArgVars, ArgTypes),
> + proc_info_get_argmodes(CalleeProcInfo, ArgModes),
> + arg_info.compute_in_and_out_vars(HLDS, ArgVars, ArgModes, ArgTypes,
> + Inputs, Outputs).
I think there is already a procedure around that does something similar
to this? Search for partition_proc_args or something like that. You
may be able to use that instead.
> +%
> +% part for computing across procedure region lifetime
> +%
> +
> +compute_interproc_region_lifetime(HLDS, RptaInfoTable, EPTable,
> + LRBeforeTable, LRAfterTable, InputRTable, OutputRTable,
> + ConstantRTable, !BornRTable, !DeadRTable, !IO) :-
> +
> + apply_live_region_born_removal_rules(HLDS, RptaInfoTable, EPTable,
> + LRBeforeTable, LRAfterTable, !BornRTable, !IO),
> +
> + apply_live_region_dead_removal_rules(HLDS, RptaInfoTable, EPTable,
> + LRBeforeTable, LRAfterTable, !DeadRTable, !IO),
> +
> + map.foldl(compute_constantR(InputRTable, OutputRTable, !.BornRTable),
> + !.DeadRTable, map.init, ConstantRTable).
> +
> +:- pred compute_constantR(proc_region_set_table::in,
> + proc_region_set_table::in, proc_region_set_table::in,
> + pred_proc_id::in, region_set::in, proc_region_set_table::in,
> + proc_region_set_table::out) is det.
> +compute_constantR(InputRTable, OutputRTable, BornRTable, PredProcId,
> DeadR,
> + !ConstantRTable) :-
> + map.lookup(InputRTable, PredProcId, InputR),
> + map.lookup(OutputRTable, PredProcId, OutputR),
> + map.lookup(BornRTable, PredProcId, BornR),
> + set.union(InputR, OutputR, IOR),
> + set.difference(IOR, BornR, IOR1),
> + set.difference(IOR1, DeadR, ConstantR),
> + svmap.set(PredProcId, ConstantR, !ConstantRTable).
> +
> +ignore_primitive_regions(HLDS, RptaInfoTable, !BornRTable, !DeadRTable,
> + !ConstantRTable, !LocalRTable, !LRBeforeTable, !LRAfterTable,
> + !VoidVarRegionTable) :-
> + map.foldl(eliminate_primitive_regions(HLDS, RptaInfoTable),
> + !.BornRTable, !BornRTable),
> + map.foldl(eliminate_primitive_regions(HLDS, RptaInfoTable),
> + !.DeadRTable, !DeadRTable),
> + map.foldl(eliminate_primitive_regions(HLDS, RptaInfoTable),
> + !.ConstantRTable, !ConstantRTable),
> + map.foldl(eliminate_primitive_regions(HLDS, RptaInfoTable),
> + !.LocalRTable, !LocalRTable),
> +
> + map.foldl(eliminate_primitive_regions_2(HLDS, RptaInfoTable),
> + !.LRBeforeTable, !LRBeforeTable),
> + map.foldl(eliminate_primitive_regions_2(HLDS, RptaInfoTable),
> + !.LRAfterTable, !LRAfterTable),
> + map.foldl(eliminate_primitive_regions_2(HLDS, RptaInfoTable),
> + !.VoidVarRegionTable, !VoidVarRegionTable).
> +
> +:- pred eliminate_primitive_regions(module_info::in, rpta_info_table::in,
> + pred_proc_id::in, region_set::in, proc_region_set_table::in,
> + proc_region_set_table::out) is det.
> +eliminate_primitive_regions(HLDS, RptaInfoTable, PredProcId, RegionSet0,
> + !RegionSetTable) :-
> + map.lookup(RptaInfoTable, PredProcId, RptaInfo),
> + RptaInfo = rpta_info(Graph, _Alpha),
> + set.fold(non_primitive_regions(HLDS, Graph), RegionSet0, set.init,
> + RegionSet),
> + svmap.det_update(PredProcId, RegionSet, !RegionSetTable).
> +
> +:- pred non_primitive_regions(module_info::in, rpt_graph::in,
> rptg_node::in,
> + region_set::in, region_set::out) is det.
> +non_primitive_regions(HLDS, Graph, Region, !RegionSet) :-
> + rptg_node_contents(Graph, Region, Content),
> + rptg_node_content_get_node_type(Content, NodeType),
> + (
> + type_util.type_is_atomic(HLDS, NodeType)
> + ->
> + true
> + ;
> + type_util.is_dummy_argument_type(HLDS, NodeType)
> + ->
> + true
> + ;
> + svset.insert(Region, !RegionSet)
> + ).
> +
> +:- pred eliminate_primitive_regions_2(module_info::in,
> rpta_info_table::in,
> + pred_proc_id::in, pp_region_set_table::in,
> proc_pp_region_set_table::in,
> + proc_pp_region_set_table::out) is det.
> +eliminate_primitive_regions_2(HLDS, RptaInfoTable, PredProcId, LRProc0,
> + !LRTable) :-
> + map.lookup(RptaInfoTable, PredProcId, RptaInfo),
> + RptaInfo = rpta_info(Graph, _Alpha),
> + map.foldl(non_primitive_regions_at_pp(HLDS, Graph), LRProc0, map.init,
> + LRProc),
> + svmap.det_update(PredProcId, LRProc, !LRTable).
> +
> +:- pred non_primitive_regions_at_pp(module_info::in, rpt_graph::in,
> + smm_data.program_point::in, region_set::in, pp_region_set_table::in,
> + pp_region_set_table::out) is det.
> +non_primitive_regions_at_pp(HLDS, Graph, PP, RegionSet0, !LRProc) :-
> + set.fold(non_primitive_regions(HLDS, Graph), RegionSet0, set.init,
> + RegionSet),
> + svmap.set(PP, RegionSet, !LRProc).
> +
> +:- func thisfile = string.
> +thisfile = "lra_lva.m".
This function is conventionally has an underscore in the name, e.g
this_file.
To be continued ...
Julien.
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to: mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions: mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------
More information about the reviews
mailing list