[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