mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 01:13:30 +00:00
compiler/rbmm.m:
compiler/rbmm.region_analysis.m:
Move all the code (one predicate) out of rbmm.m to the new module
rbmm.region_analysis.m, leaving it containing nothing but
include_module declarations.
Delete the unneeded !IO argument pair of that predicate.
compiler/mercury_compile_middle_passes.m:
Don't pass the !IO arguments to that predicate.
compiler/notes/compiler_design.html:
This file has not mentioned the rbmm package until now.
Add a short description of the package itself, but since I don't
really know what each of its component modules do, I cannot add
even short descriptions of them.
compiler/rbmm.condition_renaming.m:
compiler/rbmm.execution_path.m:
compiler/rbmm.interproc_region_lifetime.m:
compiler/rbmm.live_region_analysis.m:
compiler/rbmm.live_variable_analysis.m:
compiler/rbmm.points_to_analysis.m:
compiler/rbmm.points_to_info.m:
compiler/rbmm.region_arguments.m:
compiler/rbmm.region_instruction.m:
compiler/rbmm.region_resurrection_renaming.m:
compiler/rbmm.region_transformation.m:
Conform to the changes above.
753 lines
34 KiB
Mathematica
753 lines
34 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2007, 2009-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.region_resurrection_renaming.m.
|
|
% Main author: Quan Phan.
|
|
%
|
|
% Region resurrection is the situation where the liveness of a region
|
|
% variable along an execution path is like: live, dead, live ..., i.e., the
|
|
% variable becomes bound, then unbound, then bound again. This makes region
|
|
% variables different from regular Mercury variables.
|
|
% This module finds which renaming and reversed renaming of region variables
|
|
% are needed so that region resurrection is resolved, and after applying
|
|
% the renaming, region variables are regular Mercury variables.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module transform_hlds.rbmm.region_resurrection_renaming.
|
|
:- interface.
|
|
|
|
:- import_module hlds.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module transform_hlds.rbmm.points_to_info.
|
|
:- import_module transform_hlds.rbmm.region_instruction.
|
|
:- import_module transform_hlds.rbmm.region_liveness_info.
|
|
:- import_module transform_hlds.smm_common.
|
|
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module multi_map.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type rbmm_renaming_table ==
|
|
map(pred_proc_id, rbmm_renaming_proc).
|
|
|
|
:- type rbmm_renaming_proc ==
|
|
map(program_point, rbmm_renaming).
|
|
|
|
% Most of the time, at a program point there is only one renaming for a
|
|
% region variable. But at some resurrection points, two renamings exists
|
|
% for the resurrecting region. This should happen only in the following
|
|
% case:
|
|
% remove(R), % R -> R_Resur_1
|
|
% create(R), % R -> R_Resur_2
|
|
% (i) goal
|
|
% That's why multi_map is used.
|
|
:- type rbmm_renaming == multi_map(string, string).
|
|
|
|
:- type rbmm_renaming_annotation_table ==
|
|
map(pred_proc_id, rbmm_renaming_annotation_proc).
|
|
|
|
:- type rbmm_renaming_annotation_proc ==
|
|
map(program_point, list(region_instr)).
|
|
|
|
:- type proc_resurrection_path_table ==
|
|
map(pred_proc_id, exec_path_region_set_table).
|
|
|
|
:- type exec_path_region_set_table == map(execution_path, region_set).
|
|
|
|
:- type join_point_region_name_table ==
|
|
map(pred_proc_id, map(program_point, string)).
|
|
|
|
% This predicate traveses execution paths and detects ones in which
|
|
% resurrections of regions happen.
|
|
% For such an execution path it also calculates the regions which
|
|
% resurrect. Only procedures which contain resurrection are kept in the
|
|
% results. And for such procedures only execution paths that contain
|
|
% resurrection are kept.
|
|
%
|
|
:- pred compute_resurrection_paths(execution_path_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::in,
|
|
proc_pp_region_set_table::in, proc_pp_region_set_table::in,
|
|
proc_pp_region_set_table::in, proc_resurrection_path_table::out) is det.
|
|
|
|
% Collect join points in procedures.
|
|
% The purpose of finding join points in a procedure is because if a region
|
|
% is given different names in different execution paths leading to a join
|
|
% point, we need to unify those names at the join point.
|
|
% For this purpose, we will only collect join points in execution paths
|
|
% in which resurrection happens (i.e., the output table of by the above
|
|
% pass).
|
|
%
|
|
% A program point is a join point if it is in at least two execution
|
|
% paths and its previous points in some two execution paths are different.
|
|
%
|
|
:- pred collect_join_points(proc_resurrection_path_table::in,
|
|
execution_path_table::in, join_point_region_name_table::out) is det.
|
|
|
|
% This predicate find the execution paths in which we need to introduce
|
|
% resurrection renaming. These paths include
|
|
% 1) those in which resurrection happens (computed by
|
|
% compute_resurrection_paths),
|
|
% 2) and those in which resurrection does not happens but contain the join
|
|
% points that belong to those in 1). These can be seen as they share a
|
|
% program point with those in 1). We need to care about those paths
|
|
% because in such an execution path, we also need to rename a resurrected
|
|
% region (in the paths in 1)) so that at the join point it can be renamed
|
|
% again to the unified one. If we keep the original name we will have
|
|
% problem if the region is an output and therefore a renaming to the
|
|
% original name will be introduced after the last program point.
|
|
%
|
|
:- pred collect_paths_containing_join_points(execution_path_table::in,
|
|
join_point_region_name_table::in, proc_resurrection_path_table::in,
|
|
proc_resurrection_path_table::out) is det.
|
|
|
|
% This predicate only traverses the execution paths in which resurrection
|
|
% renaming is needed, i.e., those in the output table of the previous
|
|
% pass. It computes *renaming* at the points where a resurrected region
|
|
% becomes live.
|
|
% The result here will also only contain procedures in which resurrection
|
|
% happens and for each procedure only execution paths in which
|
|
% resurrection happens.
|
|
%
|
|
:- pred collect_region_resurrection_renaming(proc_pp_region_set_table::in,
|
|
proc_region_set_table::in, rpta_info_table::in,
|
|
proc_resurrection_path_table::in, rbmm_renaming_table::out) is det.
|
|
|
|
% This predicate collects *renaming* along the execution paths in
|
|
% procedures where region resurrection happens. It also computes
|
|
% the reversed renaming *annotations* to ensure the integrity use of
|
|
% regions.
|
|
%
|
|
:- pred collect_renaming_and_annotation(rbmm_renaming_table::in,
|
|
join_point_region_name_table::in, proc_pp_region_set_table::in,
|
|
proc_pp_region_set_table::in, proc_region_set_table::in,
|
|
rpta_info_table::in, proc_resurrection_path_table::in,
|
|
execution_path_table::in, rbmm_renaming_annotation_table::out,
|
|
rbmm_renaming_table::out) is det.
|
|
|
|
% Record the annotation for a procedure.
|
|
%
|
|
:- pred record_annotation(program_point::in, region_instr::in,
|
|
rbmm_renaming_annotation_proc::in, rbmm_renaming_annotation_proc::out)
|
|
is det.
|
|
|
|
% Make a region renaming instruction.
|
|
%
|
|
:- pred make_renaming_instruction(string::in, string::in,
|
|
region_instr::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module transform_hlds.rbmm.points_to_graph.
|
|
|
|
:- import_module assoc_list.
|
|
:- import_module counter.
|
|
:- import_module pair.
|
|
:- import_module require.
|
|
:- import_module set.
|
|
:- import_module string.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% This predicate traveses execution paths and detects ones in which
|
|
% resurrections of regions happen.
|
|
% For such an execution path it also calculates the regions which
|
|
% resurrect. Only procedures which contain resurrection are kept in the
|
|
% results. And for such procedures only execution paths that contain
|
|
% resurrection are kept.
|
|
%
|
|
compute_resurrection_paths(ExecPathTable, LRBeforeTable, LRAfterTable,
|
|
BornRTable, DeadRTable, LocalRTable,
|
|
BecomeLiveTable, BecomeDeadBeforeTable, BecomeDeadAfterTable,
|
|
PathContainsResurrectionTable) :-
|
|
map.foldl(compute_resurrection_paths_proc(LRBeforeTable, LRAfterTable,
|
|
BornRTable, DeadRTable, LocalRTable,
|
|
BecomeLiveTable, BecomeDeadBeforeTable, BecomeDeadAfterTable),
|
|
ExecPathTable, map.init, PathContainsResurrectionTable).
|
|
|
|
:- pred compute_resurrection_paths_proc(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::in,
|
|
proc_pp_region_set_table::in, proc_pp_region_set_table::in,
|
|
proc_pp_region_set_table::in, pred_proc_id::in, list(execution_path)::in,
|
|
proc_resurrection_path_table::in, proc_resurrection_path_table::out)
|
|
is det.
|
|
|
|
compute_resurrection_paths_proc(LRBeforeTable, LRAfterTable,
|
|
BornRTable, DeadRTable, LocalRTable,
|
|
BecomeLiveTable, BecomeDeadBeforeTable, BecomeDeadAfterTable,
|
|
PPId, ExecPaths, !PathContainsResurrectionTable) :-
|
|
map.lookup(LRBeforeTable, PPId, LRBeforeProc),
|
|
map.lookup(LRAfterTable, PPId, LRAfterProc),
|
|
map.lookup(BornRTable, PPId, _BornR),
|
|
map.lookup(DeadRTable, PPId, _DeadR),
|
|
map.lookup(LocalRTable, PPId, _LocalR),
|
|
map.lookup(BecomeLiveTable, PPId, BecomeLiveProc),
|
|
map.lookup(BecomeDeadBeforeTable, PPId, BecomeDeadBeforeProc),
|
|
map.lookup(BecomeDeadAfterTable, PPId, BecomeDeadAfterProc),
|
|
list.foldl(compute_resurrection_paths_exec_path(LRBeforeProc, LRAfterProc,
|
|
BecomeLiveProc, BecomeDeadBeforeProc, BecomeDeadAfterProc), ExecPaths,
|
|
map.init, PathContainsResurrectionProc),
|
|
% We only want to include procedures in which resurrection happens in this
|
|
% map.
|
|
( if map.count(PathContainsResurrectionProc) = 0 then
|
|
true
|
|
else
|
|
map.set(PPId, PathContainsResurrectionProc,
|
|
!PathContainsResurrectionTable)
|
|
).
|
|
|
|
:- pred compute_resurrection_paths_exec_path(pp_region_set_table::in,
|
|
pp_region_set_table::in, pp_region_set_table::in,
|
|
pp_region_set_table::in, pp_region_set_table::in, execution_path::in,
|
|
exec_path_region_set_table::in, exec_path_region_set_table::out) is det.
|
|
|
|
compute_resurrection_paths_exec_path(LRBeforeProc, LRAfterProc,
|
|
BecomeLiveProc, BecomeDeadBeforeProc, BecomeDeadAfterProc,
|
|
ExecPath, !ResurrectedRegionProc) :-
|
|
list.foldl3(compute_resurrection_paths_prog_point(LRBeforeProc,
|
|
LRAfterProc, BecomeLiveProc, BecomeDeadBeforeProc,
|
|
BecomeDeadAfterProc), ExecPath,
|
|
set.init, _, set.init, _, set.init, ResurrectedRegionsInExecPath),
|
|
% We want to record only execution paths in which resurrections happen.
|
|
( if set.is_empty(ResurrectedRegionsInExecPath) then
|
|
true
|
|
else
|
|
map.set(ExecPath, ResurrectedRegionsInExecPath,
|
|
!ResurrectedRegionProc)
|
|
).
|
|
|
|
:- pred compute_resurrection_paths_prog_point(pp_region_set_table::in,
|
|
pp_region_set_table::in, pp_region_set_table::in,
|
|
pp_region_set_table::in, pp_region_set_table::in,
|
|
pair(program_point, hlds_goal)::in, region_set::in, region_set::out,
|
|
region_set::in, region_set::out, region_set::in, region_set::out) is det.
|
|
|
|
compute_resurrection_paths_prog_point(LRBeforeProc, LRAfterProc,
|
|
BecomeLiveProc, BecomeDeadBeforeProc, BecomeDeadAfterProc,
|
|
ProgPoint - _, !CreatedCandidates, !RemovedCandidates,
|
|
!ResurrectedRegionsInExecPath) :-
|
|
map.lookup(LRBeforeProc, ProgPoint, _LRBeforeProgPoint),
|
|
map.lookup(LRAfterProc, ProgPoint, _LRAfterProgPoint),
|
|
map.lookup(BecomeLiveProc, ProgPoint, BecomeLiveProgPoint),
|
|
map.lookup(BecomeDeadBeforeProc, ProgPoint, BecomeDeadBeforeProgPoint),
|
|
map.lookup(BecomeDeadAfterProc, ProgPoint, BecomeDeadAfterProgPoint),
|
|
set.union(BecomeDeadAfterProgPoint, BecomeDeadBeforeProgPoint,
|
|
BecomeDeadAtProgPoint),
|
|
|
|
% Resurrected regions:
|
|
% either become live at more than one program point
|
|
% or become dead at more than one program point in an execution path.
|
|
set.intersect(!.CreatedCandidates, BecomeLiveProgPoint,
|
|
CreatedResurrectedRegions),
|
|
set.union(CreatedResurrectedRegions, !ResurrectedRegionsInExecPath),
|
|
|
|
set.intersect(!.RemovedCandidates, BecomeDeadAtProgPoint,
|
|
RemovedResurrectedRegions),
|
|
set.union(RemovedResurrectedRegions, !ResurrectedRegionsInExecPath),
|
|
|
|
% When a region is known to become live or become dead
|
|
% at one program point, it is considered a candidate for resurrection.
|
|
set.difference(set.union(!.CreatedCandidates, BecomeLiveProgPoint),
|
|
!.ResurrectedRegionsInExecPath, !:CreatedCandidates),
|
|
|
|
set.difference(set.union(!.RemovedCandidates, BecomeDeadAtProgPoint),
|
|
!.ResurrectedRegionsInExecPath, !:RemovedCandidates).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% We will only collect join points in procedures where resurrection
|
|
% happens, therefore use the PathContainsResurrectionTable just for the
|
|
% PPIds of such procedures.
|
|
%
|
|
% The new region name at a join point is formed by RegionName_jp_Number.
|
|
% If a region needs new names at several join points then Number will
|
|
% make the new names distinct.
|
|
%
|
|
collect_join_points(PathContainsResurrectionTable, ExecPathTable,
|
|
JoinPointTable) :-
|
|
map.foldl(collect_join_points_proc(ExecPathTable),
|
|
PathContainsResurrectionTable, map.init, JoinPointTable).
|
|
|
|
:- pred collect_join_points_proc(execution_path_table::in,
|
|
pred_proc_id::in, exec_path_region_set_table::in,
|
|
join_point_region_name_table::in,
|
|
join_point_region_name_table::out) is det.
|
|
|
|
collect_join_points_proc(ExecPathTable, PPId, _, !JoinPointTable) :-
|
|
map.lookup(ExecPathTable, PPId, ExecPaths),
|
|
list.foldr(
|
|
pred(ExecPath::in, Ps0::in, Ps::out) is det :- (
|
|
assoc_list.keys(ExecPath, P),
|
|
Ps = [P | Ps0]),
|
|
ExecPaths, [], Paths),
|
|
list.foldl4(collect_join_points_path(Paths), Paths, map.init, _,
|
|
counter.init(0), _, set.init, _JoinPoints, map.init, JoinPointProc),
|
|
map.set(PPId, JoinPointProc, !JoinPointTable).
|
|
|
|
:- pred collect_join_points_path(list(list(program_point))::in,
|
|
list(program_point)::in,
|
|
map(program_point, string)::in, map(program_point, string)::out,
|
|
counter::in, counter::out,
|
|
set(program_point)::in, set(program_point)::out,
|
|
map(program_point, string)::in, map(program_point, string)::out) is det.
|
|
|
|
collect_join_points_path(Paths, Path, !JP2Name, !Counter, !JoinPoints,
|
|
!JoinPointProc) :-
|
|
list.delete_all(Paths, Path, TheOtherPaths),
|
|
% We ignore the first program point in each path because
|
|
% it cannot be a join point.
|
|
( if Path = [PrevPoint, ProgPoint | ProgPoints] then
|
|
( if set.member(ProgPoint, !.JoinPoints) then
|
|
true
|
|
else
|
|
( if is_join_point(ProgPoint, PrevPoint, TheOtherPaths)then
|
|
% Try to lookup the postfix at this jp.
|
|
( if map.search(!.JP2Name, PrevPoint, JPName0)then
|
|
JPName = JPName0
|
|
else
|
|
counter.allocate(N, !Counter),
|
|
JPName = "_jp_" ++ string.int_to_string(N),
|
|
map.set(PrevPoint, JPName, !JP2Name)
|
|
),
|
|
map.set(ProgPoint, JPName, !JoinPointProc),
|
|
set.insert(ProgPoint, !JoinPoints)
|
|
else
|
|
true
|
|
)
|
|
),
|
|
collect_join_points_path(Paths, [ProgPoint | ProgPoints],
|
|
!JP2Name, !Counter, !JoinPoints, !JoinPointProc)
|
|
else
|
|
true
|
|
).
|
|
|
|
% This predicate succeeds if the first program point is a join point.
|
|
% That means it is at least in another execution path and is preceded
|
|
% by some program point, which is different from the second one.
|
|
%
|
|
:- pred is_join_point(program_point::in, program_point::in,
|
|
list(list(program_point))::in) is semidet.
|
|
|
|
is_join_point(ProgPoint, PrevProgPoint, [Path | Paths]) :-
|
|
( if is_join_point_2(ProgPoint, PrevProgPoint, Path)then
|
|
true
|
|
else
|
|
is_join_point(ProgPoint, PrevProgPoint, Paths)
|
|
).
|
|
|
|
:- pred is_join_point_2(program_point::in, program_point::in,
|
|
list(program_point)::in) is semidet.
|
|
|
|
is_join_point_2(ProgPoint, PrevProgPoint, [P1, P2 | Ps]) :-
|
|
( if P2 = ProgPoint then
|
|
P1 \= PrevProgPoint
|
|
else
|
|
is_join_point_2(ProgPoint, PrevProgPoint, [P2 | Ps])
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
collect_paths_containing_join_points(ExecPathTable, JoinPointTable,
|
|
!PathContainsResurrectionTable) :-
|
|
map.foldl(
|
|
collect_paths_containing_join_points_proc(ExecPathTable,
|
|
JoinPointTable),
|
|
!.PathContainsResurrectionTable, !PathContainsResurrectionTable).
|
|
|
|
:- pred collect_paths_containing_join_points_proc(execution_path_table::in,
|
|
join_point_region_name_table::in, pred_proc_id::in,
|
|
exec_path_region_set_table::in, proc_resurrection_path_table::in,
|
|
proc_resurrection_path_table::out) is det.
|
|
|
|
collect_paths_containing_join_points_proc(ExecPathTable, JoinPointTable, PPId,
|
|
PathContainsResurrectionProc, !PathContainsResurrectionTable) :-
|
|
map.lookup(ExecPathTable, PPId, ExecPaths),
|
|
map.values(PathContainsResurrectionProc, ResurrectedRegionsInPaths),
|
|
list.foldl(
|
|
( pred(ResurRegions::in, R0::in, R::out) is det :-
|
|
set.union(R0, ResurRegions, R)
|
|
), ResurrectedRegionsInPaths, set.init, ResurrectedRegionsProc),
|
|
map.keys(PathContainsResurrectionProc, PathsContainResurrection),
|
|
list.delete_elems(ExecPaths, PathsContainResurrection, NonResurPaths),
|
|
( if map.search(JoinPointTable, PPId, JoinPointProc) then
|
|
list.foldl(path_containing_join_point(JoinPointProc, PPId,
|
|
ResurrectedRegionsProc),
|
|
NonResurPaths, !PathContainsResurrectionTable)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred path_containing_join_point(map(program_point, string)::in,
|
|
pred_proc_id::in, set(rptg_node)::in, execution_path::in,
|
|
proc_resurrection_path_table::in, proc_resurrection_path_table::out)
|
|
is det.
|
|
|
|
path_containing_join_point(JoinPointProc, PPId, ResurrectedRegionsProc,
|
|
NonResurPath, !PathContainsResurrectionTable) :-
|
|
assoc_list.keys(NonResurPath, ProgPointsInPath),
|
|
map.foldl(find_join_points_in_path(ProgPointsInPath), JoinPointProc,
|
|
set.init, JoinPointsInThisPath),
|
|
( if set.is_empty(JoinPointsInThisPath) then
|
|
true
|
|
else
|
|
map.lookup(!.PathContainsResurrectionTable, PPId,
|
|
PathContainsResurrectionProc0),
|
|
map.det_insert(NonResurPath, ResurrectedRegionsProc,
|
|
PathContainsResurrectionProc0, PathContainsResurrectionProc),
|
|
map.set(PPId, PathContainsResurrectionProc,
|
|
!PathContainsResurrectionTable)
|
|
).
|
|
|
|
:- pred find_join_points_in_path(list(program_point)::in,
|
|
program_point::in, string::in, set(program_point)::in,
|
|
set(program_point)::out) is det.
|
|
|
|
find_join_points_in_path(ProgPointsInPath, JoinPoint, _, !JoinPoints) :-
|
|
( if list.member(JoinPoint, ProgPointsInPath) then
|
|
set.insert(JoinPoint, !JoinPoints)
|
|
else
|
|
true
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
collect_region_resurrection_renaming(BecomeLiveTable, LocalRTable,
|
|
RptaInfoTable, PathContainsResurrectionTable,
|
|
ResurrectionRenameTable) :-
|
|
map.foldl(collect_region_resurrection_renaming_proc(BecomeLiveTable,
|
|
LocalRTable, RptaInfoTable), PathContainsResurrectionTable,
|
|
map.init, ResurrectionRenameTable).
|
|
|
|
:- pred collect_region_resurrection_renaming_proc(
|
|
proc_pp_region_set_table::in, proc_region_set_table::in,
|
|
rpta_info_table::in, pred_proc_id::in, map(execution_path, region_set)::in,
|
|
rbmm_renaming_table::in, rbmm_renaming_table::out) is det.
|
|
|
|
collect_region_resurrection_renaming_proc(BecomeLiveTable, _LocalRTable,
|
|
RptaInfoTable, PPId, PathsContainResurrection,
|
|
!ResurrectionRenameTable) :-
|
|
map.lookup(BecomeLiveTable, PPId, BecomeLiveProc),
|
|
map.lookup(RptaInfoTable, PPId, RptaInfo),
|
|
RptaInfo = rpta_info(Graph, _),
|
|
map.foldl(
|
|
collect_region_resurrection_renaming_exec_path(Graph,
|
|
BecomeLiveProc),
|
|
PathsContainResurrection, map.init, ResurrectionRenameProc),
|
|
map.set(PPId, ResurrectionRenameProc, !ResurrectionRenameTable).
|
|
|
|
:- pred collect_region_resurrection_renaming_exec_path(rpt_graph::in,
|
|
pp_region_set_table::in, execution_path::in, region_set::in,
|
|
rbmm_renaming_proc::in, rbmm_renaming_proc::out) is det.
|
|
|
|
collect_region_resurrection_renaming_exec_path(Graph, BecomeLiveProc,
|
|
ExecPath, ResurrectedRegions, !ResurrectionRenameProc) :-
|
|
list.foldl2(
|
|
collect_region_resurrection_renaming_prog_point(Graph,
|
|
BecomeLiveProc, ResurrectedRegions),
|
|
ExecPath, counter.init(0), _, !ResurrectionRenameProc).
|
|
|
|
:- pred collect_region_resurrection_renaming_prog_point(rpt_graph::in,
|
|
pp_region_set_table::in, region_set::in,
|
|
pair(program_point, hlds_goal)::in, counter::in, counter::out,
|
|
rbmm_renaming_proc::in, rbmm_renaming_proc::out) is det.
|
|
|
|
collect_region_resurrection_renaming_prog_point(Graph, BecomeLiveProc,
|
|
ResurrectedRegions, ProgPoint - _, !RenamingCounter,
|
|
!ResurrectionRenameProc) :-
|
|
map.lookup(BecomeLiveProc, ProgPoint, BecomeLiveProgPoint),
|
|
set.intersect(ResurrectedRegions, BecomeLiveProgPoint,
|
|
ToBeRenamedRegions),
|
|
% We only record the program points where resurrection renaming exists.
|
|
( if set.is_empty(ToBeRenamedRegions) then
|
|
true
|
|
else
|
|
counter.allocate(N, !RenamingCounter),
|
|
set.fold(
|
|
record_renaming_prog_point(Graph, ProgPoint, N),
|
|
ToBeRenamedRegions, !ResurrectionRenameProc)
|
|
).
|
|
|
|
:- pred record_renaming_prog_point(rpt_graph::in, program_point::in, int::in,
|
|
rptg_node::in, rbmm_renaming_proc::in, rbmm_renaming_proc::out) is det.
|
|
|
|
record_renaming_prog_point(Graph, ProgPoint, RenamingCounter, Region,
|
|
!ResurrectionRenameProc) :-
|
|
RegionName = rptg_lookup_region_name(Graph, Region),
|
|
Renamed = RegionName ++ "_Resur_"
|
|
++ string.int_to_string(RenamingCounter),
|
|
( if
|
|
map.search(!.ResurrectionRenameProc, ProgPoint, RenamingProgPoint0)
|
|
then
|
|
map.set(RegionName, [Renamed], RenamingProgPoint0, RenamingProgPoint)
|
|
else
|
|
RenamingProgPoint = map.singleton(RegionName, [Renamed])
|
|
),
|
|
map.set(ProgPoint, RenamingProgPoint, !ResurrectionRenameProc).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Collect renaming at each program point.
|
|
%
|
|
% A renaming at a program point will be applied to annotations attached
|
|
% to before and after it. If the associated (atomic) goal is a procedure call
|
|
% then the renaming is also applied to its actual region arguments. If the
|
|
% goal is a construction the renaming is applied to the regions of the left
|
|
% variable.
|
|
|
|
collect_renaming_and_annotation(ResurrectionRenameTable, JoinPointTable,
|
|
LRBeforeTable, LRAfterTable, BornRTable, RptaInfoTable,
|
|
ResurrectionPathTable, ExecPathTable,
|
|
AnnotationTable, RenamingTable) :-
|
|
map.foldl2(collect_renaming_and_annotation_proc(ExecPathTable,
|
|
JoinPointTable, LRBeforeTable, LRAfterTable, BornRTable, RptaInfoTable,
|
|
ResurrectionPathTable), ResurrectionRenameTable,
|
|
map.init, AnnotationTable, map.init, RenamingTable).
|
|
|
|
:- pred collect_renaming_and_annotation_proc(execution_path_table::in,
|
|
join_point_region_name_table::in, proc_pp_region_set_table::in,
|
|
proc_pp_region_set_table::in, proc_region_set_table::in,
|
|
rpta_info_table::in, proc_resurrection_path_table::in, pred_proc_id::in,
|
|
rbmm_renaming_proc::in,
|
|
rbmm_renaming_annotation_table::in, rbmm_renaming_annotation_table::out,
|
|
rbmm_renaming_table::in, rbmm_renaming_table::out) is det.
|
|
|
|
collect_renaming_and_annotation_proc(ExecPathTable, JoinPointTable,
|
|
LRBeforeTable, LRAfterTable, BornRTable, RptaInfoTable,
|
|
ResurrectionPathTable, PPId, ResurrectionRenameProc,
|
|
!AnnotationTable, !RenamingTable) :-
|
|
map.lookup(JoinPointTable, PPId, JoinPointProc),
|
|
map.lookup(LRBeforeTable, PPId, LRBeforeProc),
|
|
map.lookup(LRAfterTable, PPId, LRAfterProc),
|
|
map.lookup(BornRTable, PPId, BornR),
|
|
map.lookup(RptaInfoTable, PPId, RptaInfo),
|
|
RptaInfo = rpta_info(Graph, _),
|
|
% Here we find all regions which resurrects in this procedure.
|
|
% This information is used at a join point to introduce renamings
|
|
% for all resurrecting regions that become live at the join point.
|
|
map.lookup(ResurrectionPathTable, PPId, PathsContainResurrection),
|
|
map.values(PathsContainResurrection, ResurrectedRegionsInPaths),
|
|
list.foldl(
|
|
pred(ResurRegions::in, R0::in, R::out) is det :- (
|
|
set.union(R0, ResurRegions, R)
|
|
),
|
|
ResurrectedRegionsInPaths, set.init, ResurrectedRegionsProc),
|
|
map.lookup(ExecPathTable, PPId, ExecPaths),
|
|
list.foldl2(collect_renaming_and_annotation_exec_path(
|
|
ResurrectionRenameProc, JoinPointProc, LRBeforeProc, LRAfterProc,
|
|
BornR, Graph, ResurrectedRegionsProc), ExecPaths,
|
|
map.init, AnnotationProc, map.init, RenamingProc),
|
|
map.set(PPId, AnnotationProc, !AnnotationTable),
|
|
map.set(PPId, RenamingProc, !RenamingTable).
|
|
|
|
% The renaming along an execution path is built up. Let's see an
|
|
% example of renamings.
|
|
% (1) R1 --> R1_1 // i.e., R1 resurrects and therefore needs renaming.
|
|
% (2) R1 --> R1_1, R2 --> R2_1
|
|
% (3) R1 --> R1_2, R2 --> R2_1 //R1 becomes live again, needs a new name.
|
|
% ...
|
|
%
|
|
:- pred collect_renaming_and_annotation_exec_path(rbmm_renaming_proc::in,
|
|
map(program_point, string)::in, pp_region_set_table::in,
|
|
pp_region_set_table::in, region_set::in, rpt_graph::in, region_set::in,
|
|
execution_path::in,
|
|
rbmm_renaming_annotation_proc::in, rbmm_renaming_annotation_proc::out,
|
|
rbmm_renaming_proc::in, rbmm_renaming_proc::out) is det.
|
|
|
|
collect_renaming_and_annotation_exec_path(_, _, _, _, _, _, _, [],
|
|
!AnnotationProc, !RenamingProc) :-
|
|
unexpected($pred, "empty execution path").
|
|
collect_renaming_and_annotation_exec_path(ResurrectionRenameProc,
|
|
JoinPointProc, LRBeforeProc, LRAfterProc, BornR, Graph,
|
|
ResurrectedRegions, [ProgPoint - _ | ProgPoint_Goals],
|
|
!AnnotationProc, !RenamingProc) :-
|
|
% This is the first program point in an execution path.
|
|
% It cannot be a join point. Renaming is needed at this point only
|
|
% when it is a resurrection point.
|
|
%
|
|
( if map.search(ResurrectionRenameProc, ProgPoint, ResurRename) then
|
|
map.set(ProgPoint, ResurRename, !RenamingProc)
|
|
else
|
|
map.set(ProgPoint, map.init, !RenamingProc)
|
|
),
|
|
collect_renaming_and_annotation_exec_path_2(ResurrectionRenameProc,
|
|
JoinPointProc, LRBeforeProc, LRAfterProc, BornR, Graph,
|
|
ResurrectedRegions, ProgPoint, ProgPoint_Goals, !AnnotationProc,
|
|
!RenamingProc).
|
|
|
|
:- pred collect_renaming_and_annotation_exec_path_2(rbmm_renaming_proc::in,
|
|
map(program_point, string)::in, pp_region_set_table::in,
|
|
pp_region_set_table::in,
|
|
region_set::in, rpt_graph::in, region_set::in, program_point::in,
|
|
execution_path::in,
|
|
rbmm_renaming_annotation_proc::in, rbmm_renaming_annotation_proc::out,
|
|
rbmm_renaming_proc::in, rbmm_renaming_proc::out) is det.
|
|
|
|
collect_renaming_and_annotation_exec_path_2(_, _, _, _, _, _, _, _, [],
|
|
!AnnotationProc, !RenamingProc).
|
|
% This means the first program point is also the last.
|
|
% We do not need to do anything more.
|
|
collect_renaming_and_annotation_exec_path_2(ResurrectionRenameProc,
|
|
JoinPointProc, LRBeforeProc, LRAfterProc, BornR, Graph,
|
|
ResurrectedRegions, PrevProgPoint, [ProgPoint - _ | ProgPoint_Goals],
|
|
!AnnotationProc, !RenamingProc) :-
|
|
% This is a program point which is not the first.
|
|
%
|
|
% A program point can belong to different execution paths, therefore
|
|
% it can be processed more than once. If a program point is a
|
|
% *join point*, the process in later execution paths may add new
|
|
% renaming information about some resurrected region(s) which does not
|
|
% resurrect in the already-processed paths covering this program point.
|
|
% To avoid updating information related to the already-processed paths
|
|
% whenever we process a join point we include the information about ALL
|
|
% resurrected regions that are live before the join point. This will
|
|
% ensure that no new renaming information arises when the program
|
|
% point is processed again.
|
|
%
|
|
% At a join point, we need to add suitable annotations to the previous
|
|
% point, i.e., ones related to the renaming at the previous point.
|
|
%
|
|
% At the last program point, we need to add annotations for any region
|
|
% parameters which resurrect.
|
|
%
|
|
map.lookup(!.RenamingProc, PrevProgPoint, PrevRenaming),
|
|
( if map.search(ResurrectionRenameProc, ProgPoint, ResurRenaming) then
|
|
% This is a resurrection point of some region(s). We need to merge
|
|
% the existing renaming at the previous point with the resurrection
|
|
% renaming here. When two renamings have the same key, i.e.,
|
|
% the related region resurrects, we will keep both renamings.
|
|
multi_map.merge(PrevRenaming, ResurRenaming, Renaming0),
|
|
map.set(ProgPoint, Renaming0, !RenamingProc)
|
|
else
|
|
% This is not a resurrection point (of any regions).
|
|
% Renaming at this point is the same as at its previous point.
|
|
map.set(ProgPoint, PrevRenaming, !RenamingProc)
|
|
),
|
|
( if map.search(JoinPointProc, ProgPoint, JoinPointName) then
|
|
% This is a join point.
|
|
% Add annotations to the previous point.
|
|
map.lookup(LRBeforeProc, ProgPoint, LRBeforeProgPoint),
|
|
map.lookup(LRAfterProc, PrevProgPoint, LRAfterPrevProgPoint),
|
|
% Not yet dead in the sense that the region is still needed to be
|
|
% removed.
|
|
set.union(LRBeforeProgPoint, LRAfterPrevProgPoint, NotYetDeadRegions),
|
|
set.intersect(ResurrectedRegions, NotYetDeadRegions,
|
|
ResurrectedAndLiveRegions),
|
|
set.fold2(
|
|
add_annotation_and_renaming_at_join_point(PrevProgPoint, Graph,
|
|
JoinPointName, PrevRenaming),
|
|
ResurrectedAndLiveRegions, !AnnotationProc, map.init, Renaming),
|
|
% We will just overwrite any existing renaming information
|
|
% at this point.
|
|
map.set(ProgPoint, Renaming, !RenamingProc)
|
|
else
|
|
true
|
|
),
|
|
(
|
|
% This is the last program point in this execution path.
|
|
ProgPoint_Goals = [],
|
|
% Add reversed renaming for regions in bornR.
|
|
set.intersect(ResurrectedRegions, BornR, ResurrectedAndBornRegions),
|
|
map.lookup(!.RenamingProc, ProgPoint, LastRenaming),
|
|
set.fold(
|
|
add_annotation_at_last_prog_point(ProgPoint, Graph,
|
|
LastRenaming),
|
|
ResurrectedAndBornRegions, !AnnotationProc)
|
|
;
|
|
ProgPoint_Goals = [_ | _],
|
|
collect_renaming_and_annotation_exec_path_2(ResurrectionRenameProc,
|
|
JoinPointProc, LRBeforeProc, LRAfterProc, BornR, Graph,
|
|
ResurrectedRegions, ProgPoint, ProgPoint_Goals, !AnnotationProc,
|
|
!RenamingProc)
|
|
).
|
|
|
|
% This predicate adds renaming annotation after the previous program
|
|
% point and records renaming from existing region name.
|
|
%
|
|
:- pred add_annotation_and_renaming_at_join_point(program_point::in,
|
|
rpt_graph::in, string::in, rbmm_renaming::in, rptg_node::in,
|
|
rbmm_renaming_annotation_proc::in, rbmm_renaming_annotation_proc::out,
|
|
rbmm_renaming::in, rbmm_renaming::out) is det.
|
|
|
|
add_annotation_and_renaming_at_join_point(PrevProgPoint, Graph, JoinPointName,
|
|
PrevRenaming, Region, !AnnotationProc, !Renaming) :-
|
|
RegionName = rptg_lookup_region_name(Graph, Region),
|
|
NewName = RegionName ++ JoinPointName,
|
|
|
|
% Record renaming at the join point if it doesn't exist yet.
|
|
map.det_insert(RegionName, [NewName], !Renaming),
|
|
|
|
% Add annotation to (after) the previous program point.
|
|
% XXX Annotations are only added for resurrected regions that have been
|
|
% renamed in this execution path (i.e., the execution path contains
|
|
% PrevProgPoint and ProgPoint).
|
|
% It seems that we have to add annotations (reverse renaming) for ones that
|
|
% have not been renamed as implemented below too. The only difference is
|
|
% that the reverse renaming is between the new name and the original name.
|
|
( if map.search(PrevRenaming, RegionName, RenamedNames) then
|
|
list.det_last(RenamedNames, CurrentName),
|
|
make_renaming_instruction(CurrentName, NewName, Annotation),
|
|
record_annotation(PrevProgPoint, Annotation, !AnnotationProc)
|
|
else
|
|
make_renaming_instruction(RegionName, NewName, Annotation),
|
|
record_annotation(PrevProgPoint, Annotation, !AnnotationProc)
|
|
).
|
|
|
|
:- pred add_annotation_at_last_prog_point(program_point::in, rpt_graph::in,
|
|
rbmm_renaming::in, rptg_node::in, rbmm_renaming_annotation_proc::in,
|
|
rbmm_renaming_annotation_proc::out) is det.
|
|
|
|
add_annotation_at_last_prog_point(ProgPoint, Graph, Renaming, Region,
|
|
!AnnotationProc) :-
|
|
RegionName = rptg_lookup_region_name(Graph, Region),
|
|
|
|
% Add annotation to (after) the program point.
|
|
% Annotations are only added for resurrected regions that have been
|
|
% renamed in this execution path.
|
|
( if map.search(Renaming, RegionName, CurrentNameList) then
|
|
CurrentName = list.det_last(CurrentNameList),
|
|
make_renaming_instruction(CurrentName, RegionName, Annotation),
|
|
record_annotation(ProgPoint, Annotation, !AnnotationProc)
|
|
else
|
|
true
|
|
).
|
|
|
|
record_annotation(ProgPoint, Annotation, !AnnotationProc) :-
|
|
( if map.search(!.AnnotationProc, ProgPoint, Annotations0) then
|
|
( if list.member(Annotation, Annotations0) then
|
|
Annotations = Annotations0
|
|
else
|
|
Annotations = [Annotation | Annotations0]
|
|
)
|
|
else
|
|
% No annotation exists at this program point yet.
|
|
Annotations = [Annotation]
|
|
),
|
|
map.set(ProgPoint, Annotations, !AnnotationProc).
|
|
|
|
make_renaming_instruction(OldRegionName, NewRegionName, RenameInstruction) :-
|
|
RenameInstruction = rename_region(OldRegionName, NewRegionName).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module transform_hlds.rbmm.region_resurrection_renaming.
|
|
%---------------------------------------------------------------------------%
|