[m-rev.] For review: Annotate the HLDS with regions
Julien Fischer
juliensf at csse.unimelb.edu.au
Wed Jun 27 15:30:56 AEST 2007
On Mon, 18 Jun 2007, Quan Phan wrote:
> Estimated hours taken: 25.
> Branch: main.
>
> Annotate the HLDS with information about regions. This includes calls to
> region builtins, extra region arguments for procedures and calls, regions
> for construction unifications.
>
> compiler/hlds_goal.m:
> Add another type constructor for how_to_construct to allow
> constructing terms in regions.
>
> compiler/goal_util.m
> compiler/hlds_out.m
> compiler/ml_unify_gen.m
> compiler/interval.m
> compiler/quantification.m
> compiler/structure_reuse.indirect.m
> Change to suit with the above additional type constructor.
>
> compiler/rbmm.condition_renaming.m:
> Change the algorithm so that the transformation needed to solve the
> problem with if-then-else is derived after the region annotated
> program has been transformed for solving the region resurrection
> problem. This is needed because the solution to region resurrection
> problem may introduce bindings of non-local region variables inside
> condition goal of an if-then-else.
>
> compiler/rbmm.execution_path.m:
> Correct a typo.
>
> compiler/rbmm.m: Add a new submodule region_transformation.
>
> compiler/rbmm.region_resurrection_renaming.m:
> Provide better comments. Reordering some predicates to suit with
> the flow of computation.
>
> compiler/rbmm.region_transformation.m:
> New file.
> Annotate the HLDS with region information to prepare for code
> generation.
...
> Index: interval.m
> ===================================================================
> RCS file: /home/mercury/mercury1/repository/mercury/compiler/interval.m,v
> retrieving revision 1.29
> diff -u -u -r1.29 interval.m
> --- interval.m 12 Jun 2007 07:21:25 -0000 1.29
> +++ interval.m 18 Jun 2007 12:35:51 -0000
> @@ -353,6 +353,11 @@
> HowToConstruct = reuse_cell(_),
> unexpected(this_file, "build_interval_info_in_goal: reuse")
> ;
> + % XXX Temporary for the time being.
> + HowToConstruct = construct_in_region(_),
> + unexpected(this_file,
> + "build_interval_info_in_goal: contruct in region")
s/contruct/construct/
> + ;
> ( HowToConstruct = construct_statically(_)
> ; HowToConstruct = construct_dynamically
> )
...
> Index: quantification.m
> ===================================================================
> RCS file: /home/mercury/mercury1/repository/mercury/compiler/quantification.m,v
> retrieving revision 1.116
> diff -u -u -r1.116 quantification.m
> --- quantification.m 12 Jun 2007 07:21:25 -0000 1.116
> +++ quantification.m 18 Jun 2007 12:37:41 -0000
> @@ -517,6 +517,8 @@
> ;
> ( How = construct_statically(_)
> ; How = construct_dynamically
> + % XXX Temporary for the time being.
> + ; How = construct_in_region(_)
> ),
> MaybeSetArgs = no,
> MaybeReuseVar = no
> @@ -1129,6 +1131,8 @@
> ;
> ( How = construct_statically(_)
> ; How = construct_dynamically
> + % XXX Temporary for the time being.
> + ; How = construct_in_region(_)
> ),
> MaybeSetArgs = no
> ),
> Index: rbmm.condition_renaming.m
> ===================================================================
> RCS file:
> /home/mercury/mercury1/repository/mercury/compiler/rbmm.condition_renaming.m,v
> retrieving revision 1.2
> diff -u -u -r1.2 rbmm.condition_renaming.m
> --- rbmm.condition_renaming.m 15 Jun 2007 11:46:11 -0000 1.2
> +++ rbmm.condition_renaming.m 18 Jun 2007 07:46:31 -0000
> @@ -16,6 +16,17 @@
> % program point so that the binding of non-local regions in the condition
> % goal of an if-then-else is resolved.
> %
> +% When reasoning about the renaming and reverse renaming needed for
... for an if-then-else we take into account ...
> +% if-then-else here we take into account the changes to regions caused by the
> +% renaming and renaming annotations needed for region resurrection.
> +% This can be viewed as if the program is transformed by the renaming
> +% and reverse renaming for region surrection first. This is to solve the
s/surrection/ressurrection/
> +% problem with region resurrection. Then that transformed program is
> +% transformed again to solve the problem with if-then-else. Note that the
> +% first transformation may add to the problem with if-then-else, e.g.,
> +% when it introduces reverse renaming to a non-local variable inside the
> +% condition goal of an if-then-else.
> +%
...
> Index: rbmm.m
> ===================================================================
> RCS file: /home/mercury/mercury1/repository/mercury/compiler/rbmm.m,v
> retrieving revision 1.4
> diff -u -u -r1.4 rbmm.m
> --- rbmm.m 15 Jun 2007 11:46:11 -0000 1.4
> +++ rbmm.m 18 Jun 2007 07:32:48 -0000
> @@ -28,6 +28,7 @@
> :- include_module region_instruction.
> :- include_module region_liveness_info.
> :- include_module region_resurrection_renaming.
> +:- include_module region_transformation.
>
> :- import_module hlds.
> :- import_module hlds.hlds_module.
> @@ -52,6 +53,10 @@
> :- import_module transform_hlds.rbmm.points_to_analysis.
> :- import_module transform_hlds.rbmm.region_instruction.
> :- import_module transform_hlds.rbmm.region_resurrection_renaming.
> +:- import_module transform_hlds.rbmm.region_transformation.
> +
> +:- import_module map.
> +:- import_module hlds.hlds_out.
Please check the coding standard regarding module imports. In particular
compiler imports should be in one block, followed by library imports in
another.
...
> Index: rbmm.region_resurrection_renaming.m
> ===================================================================
> RCS file:
> /home/mercury/mercury1/repository/mercury/compiler/rbmm.region_resurrection_renaming.m,v
> retrieving revision 1.2
> diff -u -u -r1.2 rbmm.region_resurrection_renaming.m
> --- rbmm.region_resurrection_renaming.m 15 Jun 2007 11:46:12 -0000 1.2
> +++ rbmm.region_resurrection_renaming.m 18 Jun 2007 07:49:45 -0000
> @@ -56,19 +56,49 @@
> :- type join_point_region_name_table ==
> map(pred_proc_id, map(program_point, string)).
>
> + % This predicate traveses execution paths and computes 2 pieces of
s/2/two/
> + % information:
> + % 1. The set of regions that become live before a program point
> + % (for each program point in a procedure).
> + % 2. For each procedure, compute the execution paths 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_pp_region_set_table::out, proc_resurrection_path_table::out) is det.
...
> +:- pred collect_join_points_path(list(list(program_point))::in,
> + list(program_point)::in, int::in, int::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, !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 is_join_point(ProgPoint, PrevPoint, TheOtherPaths)
> + then
> + svmap.set(ProgPoint,
> + "_jp_" ++ string.int_to_string(!.Counter),
> + !JoinPointProc),
> + svset.insert(ProgPoint, !JoinPoints),
> + !:Counter = !.Counter + 1
> + else
> + true
> + ),
> + collect_join_points_path(Paths,
> + [ProgPoint | ProgPoints], !Counter, !JoinPoints,
> + !JoinPointProc)
> + else
> + true
> + ).
Rather than using an `int' as the counter here you should use the `counter'
type from the standard library (defined in thecounter module).
...
> Index: rbmm.region_transformation.m
> ===================================================================
> RCS file: rbmm.region_transformation.m
> diff -N rbmm.region_transformation.m
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ rbmm.region_transformation.m 18 Jun 2007 06:46:46 -0000
> @@ -0,0 +1,944 @@
> +%-----------------------------------------------------------------------------%
> +% vim: ft=mercury ts=4 sw=4
> +%-----------------------------------------------------------------------------%
> +% Copyright (C) 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: rbmm.region_transformation.m
> +% Main author: quan.
> +%
> +% This module annotates the HLDS with region information.
> +% The region information includes:
> +% - Add extra region arguments (to pass regions around) to procedures and
> +% calls.
> +% - Update how_to_construct of construction unifications so that we can
> +% construct terms in a region.
> +% - Add region builtin calls (defined in region_builtin.m).
...
> +:- pred generate_list_of_region_type(int::in, mer_type::in,
> + list(mer_type)::out) is det.
> +
> +generate_list_of_region_type(N, RegType, RegTypes) :-
> + ( if N = 0
> + then
> + RegTypes = []
> + else
> + generate_list_of_region_type(N - 1, RegType, RegTypes0),
> + RegTypes = [RegType | RegTypes0]
> + ).
You can use the library function list.duplicate/2 to do that.
...
> +:- pred region_transform_proc(rpta_info_table::in, proc_region_set_table::in,
> + proc_region_set_table::in, proc_region_set_table::in,
> + proc_pp_region_list_table::in,
> + renaming_table::in, renaming_table::in, annotation_table::in,
> + renaming_annotation_table::in, renaming_annotation_table::in,
> + pred_id::in, proc_id::in, name_to_prog_var_table::in,
> + name_to_prog_var_table::out, module_info::in, module_info::out) is det.
> +
> +region_transform_proc(RptaInfoTable, ConstantRTable, DeadRTable, BornRTable,
> + ActualRegionArgTable, ResurRenamingTable, IteRenamingTable,
> + AnnotationTable, ResurRenamingAnnoTable, IteRenamingAnnoTable,
> + PredId, ProcId, !NameToVarTable, !ModuleInfo) :-
> + PPId = proc(PredId, ProcId),
> + module_info_pred_proc_info(!.ModuleInfo, PPId, PredInfo, ProcInfo0),
> + fill_goal_path_slots(!.ModuleInfo, ProcInfo0, ProcInfo1),
> + proc_info_get_varset(ProcInfo1, VarSet0),
> + proc_info_get_vartypes(ProcInfo1, VarTypes0),
> + proc_info_get_headvars(ProcInfo1, HeadVars0),
> + proc_info_get_argmodes(ProcInfo1, ActualArgModes0),
> + proc_info_get_goal(ProcInfo1, Goal0),
> + map.lookup(RptaInfoTable, PPId, rpta_info(Graph, _)),
> + map.lookup(ConstantRTable, PPId, ConstantR),
> + map.lookup(DeadRTable, PPId, DeadR),
> + map.lookup(BornRTable, PPId, BornR),
> + map.lookup(ActualRegionArgTable, PPId, ActualRegionArgProc),
> + ( if map.search(ResurRenamingTable, PPId, ResurRenamingProc0)
> + then
> + ResurRenamingProc = ResurRenamingProc0,
> + map.lookup(ResurRenamingAnnoTable, PPId,
> + ResurRenamingAnnoProc)
> + else
> + ResurRenamingProc = map.init,
> + ResurRenamingAnnoProc = map.init
> + ),
> + ( if map.search(IteRenamingTable, PPId, IteRenamingProc0)
> + then
> + IteRenamingProc = IteRenamingProc0,
> + map.lookup(IteRenamingAnnoTable, PPId,
> + IteRenamingAnnoProc)
> + else
> + IteRenamingProc = map.init,
> + IteRenamingAnnoProc = map.init
> + ),
> + map.lookup(AnnotationTable, PPId, AnnotationProc),
> +
> + NameToVar0 = map.init,
> + annotate_proc(!.ModuleInfo, PredInfo, Graph, ConstantR, DeadR, BornR,
> + ActualRegionArgProc, ResurRenamingProc, IteRenamingProc,
> + AnnotationProc, ResurRenamingAnnoProc, IteRenamingAnnoProc,
> + VarSet0, _, VarTypes0, _, HeadVars0, _, ActualArgModes0, _,
> + Goal0, _, NameToVar0, NameToVar, ProcInfo1, ProcInfo),
You will need to recompute the instmap deltas for the procedure at this point,
e.g. something like
RecomputeAtomic = yes,
recompute_instmap_delta_proc(RecomputeAtomic, ProcInfo2, ProcInfo, !ModuleInfo),
(where ProcInfo2 is the output of annotate_proc/26)
You may also need to recompute the purity at this point as well, i.e. call
repurity_check_proc/4.
> +
> + module_info_set_pred_proc_info(PPId, PredInfo, ProcInfo, !ModuleInfo),
> + svmap.det_insert(PPId, NameToVar, !NameToVarTable).
> +
> + % Currently for a procedure we annotate the following information:
> + % 1. VarSet with region variables
> + % 2. VarTypes with region variables and their types
> + % 3. HeadVars with formal region arguments
> + % 4. ActualHeadModes with the modes for region variables
> + % 5. Body:
> + % + new region arguments at calls
> + % + new calls to region instructions
> + %
> + % XXX What about head_var_caller_liveness and
> + % prog_sub_info -> arg_pass_info
> + %
> + %
> +:- pred annotate_proc(module_info::in, pred_info::in, rpt_graph::in,
> + region_set::in, region_set::in, region_set::in,
> + pp_region_list_table::in, renaming_proc::in, renaming_proc::in,
> + annotation_proc::in, renaming_annotation_proc::in,
> + renaming_annotation_proc::in, prog_varset::in, prog_varset::out,
> + vartypes::in, vartypes::out, list(prog_var)::in, list(prog_var)::out,
> + list(mer_mode)::in, list(mer_mode)::out, hlds_goal::in, hlds_goal::out,
> + name_to_prog_var::in, name_to_prog_var::out, proc_info::in,
> + proc_info::out) is det.
> +
> +annotate_proc(ModuleInfo, PredInfo, Graph, ConstantR, DeadR, BornR,
> + ActualRegionArgProc, ResurRenamingProc, IteRenamingProc,
> + AnnotationProc, ResurRenamingAnnoProc, IteRenamingAnnoProc,
> + !VarSet, !VarTypes, !HeadVars, !ActualArgModes, !Goal,
> + !NameToVar, !ProcInfo) :-
> + region_transform_goal(ModuleInfo, Graph, ResurRenamingProc,
> + IteRenamingProc, ActualRegionArgProc,
> + AnnotationProc, ResurRenamingAnnoProc, IteRenamingAnnoProc,
> + !Goal, !NameToVar, !VarSet, !VarTypes),
> +
> + % Computing head_vars.
> + % Note that formal region arguments are not subjected to renaming.
> + set.to_sorted_list(ConstantR, LConstantR),
> + set.to_sorted_list(DeadR, LDeadR),
> + set.to_sorted_list(BornR, LBornR),
> + FormalInputNodes = LConstantR ++ LDeadR,
> + FormalNodes = FormalInputNodes ++ LBornR,
> + list.map_foldl3(node_to_reg_var(Graph), FormalNodes, FormalRegionArgs,
> + !NameToVar, !VarSet, !VarTypes),
> +
> + % Computing actual_head_modes.
> + InMode = in_mode,
> + OutMode = out_mode,
> + list.foldl(generate_mode_list(InMode), FormalInputNodes, [], InModes),
> + list.foldl(generate_mode_list(OutMode), LBornR, [], OutModes),
> +
> + % One thing to notice here is that the output of a function needs
> + % to be the last argument.
> + PredOrFunc = pred_info_is_pred_or_func(PredInfo),
> + (
> + PredOrFunc = pf_predicate,
> + !:HeadVars = !.HeadVars ++ FormalRegionArgs,
> + !:ActualArgModes = !.ActualArgModes ++ InModes ++ OutModes
> + ;
> + PredOrFunc = pf_function,
> + list.split_last_det(!.HeadVars, BeforeLastHeadVar, LastHeadVar),
> + !:HeadVars = BeforeLastHeadVar ++ FormalRegionArgs
> + ++ [LastHeadVar],
> + list.split_last_det(!.ActualArgModes, BeforeLastHeadMode,
> + LastHeadMode),
> + !:ActualArgModes = BeforeLastHeadMode ++ InModes
> + ++ OutModes ++ [LastHeadMode]
> + ),
> +
> + proc_info_set_varset(!.VarSet, !ProcInfo),
> + proc_info_set_goal(!.Goal, !ProcInfo),
> + proc_info_set_vartypes(!.VarTypes, !ProcInfo),
> + proc_info_set_headvars(!.HeadVars, !ProcInfo),
> + proc_info_set_argmodes(!.ActualArgModes, !ProcInfo).
> +
> +:- pred generate_mode_list(mer_mode::in, rptg_node::in, list(mer_mode)::in,
> + list(mer_mode)::out) is det.
> +
> +generate_mode_list(Mode, _Node, Modes0, [Mode | Modes0]).
> +
> + % Basically, we will turn this atomic goal and all the region
> + % annotations attached to (before and after) it into a
> + % conjunction (even when there is no annotation). If the
Why don't you just leave them alone if there is no annotation?
...
> + %
> + % Note: When both renamings (for resurrection and if-then-else) of a
> + % region exist at a program point, we will apply the resurrection one.
> + % This is due to the fact that when reasonning about what renaming is
s/reasonning/reasoning/
> + % needed for if-then-else we have taken into account the changes
> + % caused by renaming and annotations needed for resurrection problem.
> + %
... for the ressurrection problem.
> +:- pred region_transform_goal(module_info::in, rpt_graph::in,
> + renaming_proc::in, renaming_proc::in, pp_region_list_table::in,
> + annotation_proc::in, renaming_annotation_proc::in,
> + renaming_annotation_proc::in, hlds_goal::in, hlds_goal::out,
> + name_to_prog_var::in, name_to_prog_var::out,
> + prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
> +
> +region_transform_goal(ModuleInfo, Graph, ResurRenamingProc, IteRenamingProc,
> + ActualRegionArgProc, AnnotationProc, ResurRenamingAnnoProc,
> + IteRenamingAnnoProc, !Goal, !NameToVar, !VarSet, !VarTypes) :-
> + !.Goal = hlds_goal(GoalExpr0, Info),
> + ( goal_is_atomic(GoalExpr0)
> + ->
> + ProgPoint = program_point_init(Info),
> + ProgPoint = pp(Context, _),
> + find_renamings_at_prog_point(ResurRenamingProc, IteRenamingProc,
> + ProgPoint, ResurRenaming, IteRenaming),
> +
> + % Depending on the expression, this call will annotate
> + % - a call with actual region arguments,
> + % - a construction unification with a region to construct in.
> + region_transform_goal_expr(Graph, ResurRenaming,
> + IteRenaming, ActualRegionArgProc, ProgPoint,
> + GoalExpr0, GoalExpr, !NameToVar, !VarSet, !VarTypes),
> +
> + % Assignment unifications due to ite renaming.
> + assignments_from_ite_renaming_anno(IteRenamingAnnoProc,
> + ProgPoint, !NameToVar, !VarSet, !VarTypes,
> + [], IteRenamingAssignments),
> +
> + % Region instructions before and after this program point.
> + ( map.search(AnnotationProc, ProgPoint,
> + before_after(Before, After))
> + ->
> + % Region instructions before this program point.
> + list.foldl4(region_instruction_to_conj(ModuleInfo,
> + Context, ResurRenaming, IteRenaming), Before,
> + !NameToVar, !VarSet, !VarTypes,
> + IteRenamingAssignments, Conjs1),
> +
> + % The goal at this program point itself.
> + Conjs2 = Conjs1 ++ [hlds_goal(GoalExpr, Info)],
> +
> + % Region instructions after this program point.
> + list.foldl4(region_instruction_to_conj(ModuleInfo,
> + Context, ResurRenaming, IteRenaming), After,
> + !NameToVar, !VarSet, !VarTypes,
> + Conjs2, Conjs3)
> + ;
> + % The goal at this program point itself.
> + Conjs3 = IteRenamingAssignments ++
> + [hlds_goal(GoalExpr, Info)]
> + ),
> +
> + % Assignment unifications due to region resurrection renaming.
> + assignments_from_resur_renaming_anno(ResurRenamingAnnoProc,
> + ProgPoint, IteRenaming, !NameToVar, !VarSet, !VarTypes,
> + Conjs3, Conjs),
> +
> + !:Goal = hlds_goal(conj(plain_conj, Conjs), Info)
> + ;
> + region_transform_compound_goal(ModuleInfo, Graph,
> + ResurRenamingProc, IteRenamingProc, ActualRegionArgProc,
> + AnnotationProc, ResurRenamingAnnoProc,
> + IteRenamingAnnoProc, !Goal, !NameToVar, !VarSet,
> + !VarTypes)
> + ).
> +
> +:- pred region_transform_goal_expr(rpt_graph::in, renaming::in,
> + renaming::in, pp_region_list_table::in, program_point::in,
> + hlds_goal_expr::in, hlds_goal_expr::out, name_to_prog_var::in,
> + name_to_prog_var::out, prog_varset::in, prog_varset::out,
> + vartypes::in, vartypes::out) is det.
> +
> + % Annotate procedure calls with actual region arguments.
> + %
> +region_transform_goal_expr(Graph, ResurRenaming, IteRenaming,
> + ActualRegionArgProc, ProgPoint, !GoalExpr, !NameToVar, !VarSet,
> + !VarTypes) :-
> + !.GoalExpr = plain_call(CalleePredId, CalleeProcId, Args0, Builtin,
> + Context, Name),
> + % XXX Callee may be a builtin or an imported procedure that we have
> + % not analysed, we just ignore such a call for now.
> + ( if map.search(ActualRegionArgProc, ProgPoint, ActualNodes0)
> + then ActualNodes = ActualNodes0
> + else ActualNodes = []
> + ),
> + list.map_foldl3(node_to_reg_var_with_both_renamings(Graph,
> + ResurRenaming, IteRenaming),
> + ActualNodes, ActualRegionArgs, !NameToVar, !VarSet, !VarTypes),
> + Args = Args0 ++ ActualRegionArgs,
> + !:GoalExpr = plain_call(CalleePredId, CalleeProcId, Args, Builtin,
> + Context, Name).
> +
> + % Annotate construction unifications with regions to construct in.
> + %
> +region_transform_goal_expr(Graph, ResurRenaming, IteRenaming,
> + _, _, !GoalExpr, !NameToVar, !VarSet, !VarTypes) :-
> + !.GoalExpr = unify(LHS, RHS, Mode, Unification0, Context),
> + annotate_constructions_unification(Graph, ResurRenaming, IteRenaming,
> + Unification0, Unification, !NameToVar, !VarSet, !VarTypes),
> + !:GoalExpr = unify(LHS, RHS, Mode, Unification, Context).
> +
> +region_transform_goal_expr(_, _, _, _, _, !GoalExpr, !NameToVar,
> + !VarSet, !VarTypes) :-
> + !.GoalExpr = generic_call(_, _, _, _),
> + sorry(this_file,
> + "region_transform_goal_expr: generic call is not handled.").
> +
> +region_transform_goal_expr(_, _, _, _, _, !GoalExpr, !NameToVar,
> + !VarSet, !VarTypes) :-
> + !.GoalExpr = call_foreign_proc(_, _, _, _, _, _, _),
> + sorry(this_file, "region_transform_goal_expr: " ++
> + "call to foreign procedure is not handled").
> +
> +region_transform_goal_expr(_, _, _, _, _, !GoalExpr, !NameToVar,
> + !VarSet, !VarTypes) :-
> + ( !.GoalExpr = conj(_, [])
> + ; !.GoalExpr = disj([])
> + ).
> +
> +region_transform_goal_expr(_, _, _, _, _, !GoalExpr, !NameToVar,
> + !VarSet, !VarTypes) :-
> + ( !.GoalExpr = conj(_, [_ | _])
> + ; !.GoalExpr = disj([_ | _])
> + ; !.GoalExpr = if_then_else(_, _, _, _)
> + ; !.GoalExpr = negation(_)
> + ; !.GoalExpr = switch(_, _, _)
> + ; !.GoalExpr = scope(_, _)
> + ; !.GoalExpr = shorthand(_)
> + ),
> + unexpected(this_file,
> + "region_transform_goal_expr: encounter compound goal").
> +
...
> +:- pred annotate_constructions_unification(rpt_graph::in, renaming::in,
> + renaming::in, unification::in, unification::out,
> + name_to_prog_var::in, name_to_prog_var::out,
> + prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
> +
> +annotate_constructions_unification(Graph, ResurRenaming, IteRenaming,
> + !Unification, !NameToVar, !VarSet, !VarTypes) :-
> + !.Unification = construct(Var, ConsId, Args, ArgModes, _HowToConstruct0,
> + IsUnique, SubInfo),
> + get_node_by_variable(Graph, Var, Node),
> + Name = rptg_lookup_region_name(Graph, Node),
> + name_to_reg_var_with_both_renamings(Name, ResurRenaming, IteRenaming,
> + RegVar, !NameToVar, !VarSet, !VarTypes),
> + HowToConstruct = construct_in_region(RegVar),
> + !:Unification = construct(Var, ConsId, Args, ArgModes, HowToConstruct,
> + IsUnique, SubInfo).
> +
> +annotate_constructions_unification(_, _, _, !Unification, !VarSet,
> + !VarTypes, !NameToVar) :-
> + (
> + ( !.Unification = deconstruct(_, _, _, _, _, _)
> + ; !.Unification = assign(_, _)
> + ; !.Unification = simple_test(_, _)
> + ),
> + true
Delete 'true'.
> + ;
> + !.Unification = complicated_unify(_, _, _),
> + unexpected(this_file, "annotate_construction_unification: "
> + ++ "encounter complicated unify")
> + ).
> +
> + % The process here is related to the way we treat the unifications
> + % between the switch vars and a constant or a functor of arity zero.
> + % For more information about the treatment, see rbmm.execution_path.m.
> + % These unifications are not explicitly present in the goal but we
> + % still need to insert annotations derived for them into the goal.
> + % Therefore we will make a conjunction of the annotations attached to an
> + % implicit unification. We transform the goal separately. Then we make
> + % another conjunction of the conjunction and the transformed goal.
> + % Finally, we try to flatten this new conjunction.
> + %
> +:- pred region_transform_case(module_info::in, rpt_graph::in,
> + renaming_proc::in, renaming_proc::in, pp_region_list_table::in,
> + annotation_proc::in, renaming_annotation_proc::in,
> + renaming_annotation_proc::in, hlds_goal::in, case::in, case::out,
> + name_to_prog_var::in, name_to_prog_var::out,
> + prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
> +
> +region_transform_case(ModuleInfo, Graph, ResurRenamingProc,
> + IteRenamingProc, ActualRegionArgProc, AnnotationProc,
> + ResurRenamingAnnoProc, IteRenamingAnnoProc, Switch,
> + case(ConsId, !.Goal), case(ConsId, !:Goal),
> + !NameToVar, !VarSet, !VarTypes) :-
> + ( ( ConsId = cons(_, 0)
> + ; ConsId = int_const(_)
> + ; ConsId = string_const(_)
> + ; ConsId = float_const(_)
> + ),
> + Switch = hlds_goal(switch(_, _, _), Info)
> + ->
> + ProgPoint = program_point_init(Info),
> + ProgPoint = pp(Context, _),
> + find_renamings_at_prog_point(ResurRenamingProc, IteRenamingProc,
> + ProgPoint, ResurRenaming, IteRenaming),
> +
> + % Assignment unifications due to ite renaming.
> + assignments_from_ite_renaming_anno(IteRenamingAnnoProc,
> + ProgPoint, !NameToVar, !VarSet, !VarTypes,
> + [], IteRenamingAssignments),
> +
> + % Region instructions before and after this program
> + % point.
> + ( map.search(AnnotationProc, ProgPoint,
> + before_after(Before, After))
> + ->
> + % Region instructions before this program point.
> + list.foldl4(region_instruction_to_conj(
> + ModuleInfo, Context, ResurRenaming,
> + IteRenaming), Before, !NameToVar,
> + !VarSet, !VarTypes,
> + IteRenamingAssignments, Conjs1),
> +
> + % Region instructions after this program point.
> + list.foldl4(region_instruction_to_conj(
> + ModuleInfo, Context, ResurRenaming,
> + IteRenaming), After, !NameToVar,
> + !VarSet, !VarTypes, Conjs1, Conjs2)
> + ;
> + Conjs2 = IteRenamingAssignments
> + ),
> +
> + % Assignment unifications due to region resurrection
> + % renaming.
> + assignments_from_resur_renaming_anno(ResurRenamingAnnoProc,
> + ProgPoint, IteRenaming, !NameToVar, !VarSet, !VarTypes,
> + Conjs2, Conjs),
> +
> + RemovedGoal = hlds_goal(conj(plain_conj, Conjs), Info)
> + ;
> + Switch = hlds_goal(_, Info),
> + RemovedGoal = hlds_goal(conj(plain_conj, []), Info)
> + ),
> + region_transform_goal(ModuleInfo, Graph, ResurRenamingProc,
> + IteRenamingProc, ActualRegionArgProc, AnnotationProc,
> + ResurRenamingAnnoProc, IteRenamingAnnoProc, !Goal, !NameToVar,
> + !VarSet, !VarTypes),
> + flatten_conjunction([RemovedGoal, !.Goal], FlatConjs),
> + Switch = hlds_goal(_, ConjsInfo),
> + !:Goal = hlds_goal(conj(plain_conj, FlatConjs), ConjsInfo).
> +
> +:- pred find_renamings_at_prog_point(renaming_proc::in, renaming_proc::in,
> + program_point::in, renaming::out, renaming::out) is det.
> +
> +find_renamings_at_prog_point(ResurRenamingProc, IteRenamingProc, ProgPoint,
> + ResurRenaming, IteRenaming) :-
> + ( if map.search(ResurRenamingProc, ProgPoint, ResurRenaming0)
> + then
> + ResurRenaming = ResurRenaming0
> + else
> + ResurRenaming = map.init
> + ),
> + ( if map.search(IteRenamingProc, ProgPoint, IteRenaming0)
> + then
> + IteRenaming = IteRenaming0
> + else
> + IteRenaming = map.init
> + ).
> +
> +:- pred assignments_from_ite_renaming_anno(renaming_annotation_proc::in,
> + program_point::in, name_to_prog_var::in, name_to_prog_var::out,
> + prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
> + hlds_goals::in, hlds_goals::out) is det.
> +
> +assignments_from_ite_renaming_anno(IteRenamingAnnoProc, ProgPoint,
> + !NameToVar, !VarSet, !VarTypes, !IteRenamingAssignments) :-
> + % Assignment unifications due to ite renaming.
> + ( map.search(IteRenamingAnnoProc, ProgPoint, IteRenamingAnnos)
> + ->
> + list.foldl4( ite_renaming_annotation_to_assignment,
> + IteRenamingAnnos, !NameToVar, !VarSet, !VarTypes,
> + !IteRenamingAssignments)
> + ;
> + true
> + ).
> +
> +:- pred assignments_from_resur_renaming_anno(renaming_annotation_proc::in,
> + program_point::in, renaming::in, name_to_prog_var::in,
> + name_to_prog_var::out, prog_varset::in, prog_varset::out,
> + vartypes::in, vartypes::out, hlds_goals::in, hlds_goals::out) is det.
> +
> +assignments_from_resur_renaming_anno(ResurRenamingAnnoProc, ProgPoint,
> + IteRenaming, !NameToVar, !VarSet, !VarTypes, !Conjs) :-
> + ( map.search(ResurRenamingAnnoProc, ProgPoint,
> + ResurRenamingAnnos)
> + ->
> + list.foldl4(resur_renaming_annotation_to_assignment(
> + IteRenaming), ResurRenamingAnnos, !NameToVar, !VarSet,
> + !VarTypes, !Conjs)
> + ;
> + true
> + ).
> +
> + % XXX This flatten predicate is copied and pasted from
> + % prop_mode_constraints.m.
> + %
> + % flatten_conjunction(!Goals) flattens the conjunction Goals - that
> + % is, moves the conjuncts from nested conjunctions into Goals.
> + %
> +:- pred flatten_conjunction(hlds_goals::in, hlds_goals::out) is det.
> +
> +flatten_conjunction(!Goals) :-
> + list.foldr(add_to_conjunction, !.Goals, [], !:Goals).
> +
> + % add_to_conjunction(Goal, !Goals) adds Goal to the front of
> + % the conjunction Goals. It keeps the conjunction flat, so
> + % nested conjunctions are scrapped and their conjuncts prepended
> + % to Goals.
> + %
> +:- pred add_to_conjunction(hlds_goal::in, hlds_goals::in, hlds_goals::out)
> + is det.
> +
> +add_to_conjunction(Goal, !Goals) :-
> + ( Goal = hlds_goal(conj(plain_conj, SubGoals), _) ->
> + list.append(SubGoals, !Goals)
> + ;
> + list.cons(Goal, !Goals)
> + ).
> +
> +:- pred node_to_reg_var(rpt_graph::in, rptg_node::in,
> + prog_var::out, name_to_prog_var::in, name_to_prog_var::out,
> + prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
Add a comment describing what this predicate does.
> +
> +node_to_reg_var(Graph, Node, RegVar, !NameToVar, !VarSet,
> + !VarTypes) :-
> + RegName = rptg_lookup_region_name(Graph, Node),
> + name_to_reg_var(RegName, RegVar, !NameToVar, !VarSet, !VarTypes).
> +
> +:- pred name_to_reg_var(string::in, prog_var::out,
> + name_to_prog_var::in, name_to_prog_var::out,
> + prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
> +
> +name_to_reg_var(Name, RegVar, !NameToVar, !VarSet, !VarTypes) :-
> + ( if map.search(!.NameToVar, Name, RegVar0)
> + then
> + RegVar = RegVar0
> + else
> + varset.new_named_var(!.VarSet, Name, RegVar, !:VarSet),
> + svmap.det_insert(RegVar, make_region_type, !VarTypes),
> + svmap.det_insert(Name, RegVar, !NameToVar)
> + ).
> +
> +:- pred node_to_reg_var_with_both_renamings(rpt_graph::in, renaming::in,
> + renaming::in, rptg_node::in, prog_var::out,
> + name_to_prog_var::in, name_to_prog_var::out,
> + prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
> +
> +node_to_reg_var_with_both_renamings(Graph, ResurRenaming, IteRenaming,
> + Node, RegVar, !NameToVar, !VarSet, !VarTypes) :-
> + RegName = rptg_lookup_region_name(Graph, Node),
> + name_to_reg_var_with_both_renamings(RegName, ResurRenaming, IteRenaming,
> + RegVar, !NameToVar, !VarSet, !VarTypes).
> +
> +:- pred name_to_reg_var_with_renaming(string::in, renaming::in,
> + prog_var::out, name_to_prog_var::in, name_to_prog_var::out,
> + prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
> +
> +name_to_reg_var_with_renaming(Name0, ResurRenaming, RegVar,
> + !NameToVar, !VarSet, !VarTypes) :-
> + ( if map.search(ResurRenaming, Name0, Name1)
> + then
> + Name = Name1
> + else
> + Name = Name0
> + ),
> + name_to_reg_var(Name, RegVar, !NameToVar, !VarSet, !VarTypes).
> +
> + % Resurrection renaming will be applied first. If a renaming exists
> + % for the name (therefore the name is changed to another name) then
> + % ite renaming need not to be applied because actually it is not
> + % applicable anymore.
> +:- pred name_to_reg_var_with_both_renamings(string::in, renaming::in,
> + renaming::in, prog_var::out,
> + name_to_prog_var::in, name_to_prog_var::out,
> + prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
> +
> +name_to_reg_var_with_both_renamings(Name0, ResurRenaming, IteRenaming,
> + RegVar, !NameToVar, !VarSet, !VarTypes) :-
> + ( if map.search(ResurRenaming, Name0, Name1)
> + then Name = Name1
> + else
> + ( if map.search(IteRenaming, Name0, Name2)
> + then Name = Name2
> + else Name = Name0
> + )
> + ),
> + name_to_reg_var(Name, RegVar, !NameToVar, !VarSet, !VarTypes).
> +
...
> +:- pred region_instruction_to_conj(module_info::in, term.context::in,
> + renaming::in, renaming::in, string::in,
> + name_to_prog_var::in, name_to_prog_var::out,
> + prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
> + hlds_goals::in, hlds_goals::out) is det.
> +
> + % Instruction is of the form: "Tx: xxxxxx R..."
> + % The first x is the number of the rule, which is not important here.
> + % The next 6 x is either "remove" or "create", the last part is the
> + % region name. This region name will be subjected to renaming due to
> + % if-then-else and region resurrection.
> + % This predicate turns such an instruction into a call to a suitable
> + % region builtin.
> + %
Move this comment above the predicate declaration.
> +region_instruction_to_conj(ModuleInfo, Context, ResurRenaming, IteRenaming,
> + Instruction, !NameToVar, !VarSet, !VarTypes, Conjs0, Conjs) :-
> + string.substring(Instruction, 4, 6, Kind),
> + string.substring(Instruction, 11, string.length(Instruction) - 11,
> + RegionName),
> + name_to_reg_var_with_both_renamings(RegionName, ResurRenaming,
> + IteRenaming, RegVar, !NameToVar, !VarSet, !VarTypes),
> + (
> + Kind = "create"
> + ->
> + generate_simple_call(mercury_region_builtin_module,
> + "create_region", pf_predicate, only_mode, detism_det,
> + purity_impure, [RegVar], [], [RegVar - free_inst],
> + ModuleInfo, Context, CallGoal)
> + ;
> + Kind = "remove"
> + ->
> + generate_simple_call(mercury_region_builtin_module,
> + "remove_region", pf_predicate, only_mode, detism_det,
> + purity_impure, [RegVar], [], [RegVar - ground_inst],
> + ModuleInfo, Context, CallGoal)
> + ;
> + unexpected(this_file, "region_instruction_to_conj: " ++
> + "encounter unknown region instruction")
> + ),
> + Conjs = Conjs0 ++ [CallGoal].
> +
> + % A resurrection renaming annotation is in the form Rx = Rx_resur_y,
> + % where Rx is the original name of the region, the other is the one
> + % the region is renamed to.
> + % This predicate converts the anotation into an assigment unification.
> + % The original name of the region is subjected to the renaming due to
> + % if-then-else, if such a renaming exists at the current program point.
> + %
> +:- pred resur_renaming_annotation_to_assignment(renaming::in, string::in,
> + name_to_prog_var::in, name_to_prog_var::out,
> + prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
> + hlds_goals::in, hlds_goals::out) is det.
> +
> +resur_renaming_annotation_to_assignment(IteRenaming, Annotation,
> + !NameToVar, !VarSet, !VarTypes, Conjs0, Conjs) :-
> + ( if string.sub_string_search(Annotation, "=", Index)
> + then
> + Left = string.substring(Annotation, 0, Index - 1),
> + Right = string.substring(Annotation, Index + 2,
> + string.length(Annotation) - (Index + 2)),
> + % Only the left region needs to be renamed. Ite renaming
> + % does not involve one on the right side.
> + name_to_reg_var_with_renaming(Left, IteRenaming,
> + LeftRegVar, !NameToVar, !VarSet, !VarTypes),
> + name_to_reg_var(Right, RightRegVar, !NameToVar,
> + !VarSet, !VarTypes),
> + make_assignment_goal(LeftRegVar, RightRegVar,
> + "resurrection renaming annotation",
> + AssignmentGoal),
> + Conjs = Conjs0 ++ [AssignmentGoal]
> + else
> + unexpected(this_file, "resur_renaming_annotation_to_assignment: "
> + ++ "annotation is not assigment")
> + ).
> +
> + % This predicate turns a renaming annotation due to if-then-else into
> + % an assignment. No renaming needs to be applied to the
> + % if-then-else renaming annotations.
> + %
> +:- pred ite_renaming_annotation_to_assignment(string::in,
> + name_to_prog_var::in, name_to_prog_var::out,
> + prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
> + hlds_goals::in, hlds_goals::out) is det.
> +
> +ite_renaming_annotation_to_assignment(Annotation, !NameToVar,
> + !VarSet, !VarTypes, Conjs0, Conjs) :-
> + ( if string.sub_string_search(Annotation, "=", Index)
> + then
> + Left = string.substring(Annotation, 0, Index - 1),
> + Right = string.substring(Annotation, Index + 2,
> + string.length(Annotation) - (Index + 2)),
> + name_to_reg_var(Left, LeftRegVar, !NameToVar,
> + !VarSet, !VarTypes),
> + name_to_reg_var(Right, RightRegVar, !NameToVar,
> + !VarSet, !VarTypes),
> + make_assignment_goal(LeftRegVar, RightRegVar,
> + "ite renaming annotation", AssignmentGoal),
> + Conjs = Conjs0 ++ [AssignmentGoal]
> + else
> + unexpected(this_file, "ite_renaming_annotation_to_assignment: "
> + ++ "annotation is not assignment")
> + ).
> +
> +:- pred make_assignment_goal(prog_var::in, prog_var::in, string::in,
> + hlds_goal::out) is det.
> +
> +make_assignment_goal(LeftRegVar, RightRegVar, Context, AssignmentGoal) :-
> + AssignmentExpr = unify(LeftRegVar, rhs_var(RightRegVar),
> + out_mode - in_mode,
> + assign(LeftRegVar, RightRegVar),
> + unify_context(
> + umc_implicit(Context),
> + []
> + )
> + ),
> + NonLocals = set.from_list([LeftRegVar, RightRegVar]),
> + instmap_delta_from_assoc_list([LeftRegVar - free_inst,
> + RightRegVar - ground_inst], InstmapDelta),
> + goal_info_init(NonLocals, InstmapDelta, detism_det,
> + purity_pure, AssignmentInfo),
> + AssignmentGoal = hlds_goal(AssignmentExpr, AssignmentInfo).
> +
...
> Index: structure_reuse.indirect.m
> ===================================================================
> RCS file:
> /home/mercury/mercury1/repository/mercury/compiler/structure_reuse.indirect.m,v
> retrieving revision 1.10
> diff -u -u -r1.10 structure_reuse.indirect.m
> --- structure_reuse.indirect.m 12 Jun 2007 07:21:26 -0000 1.10
> +++ structure_reuse.indirect.m 18 Jun 2007 12:50:00 -0000
> @@ -302,6 +302,8 @@
> ;
> ( HowToConstruct = construct_dynamically
> ; HowToConstruct = reuse_cell(_)
> + % XXX Temporary for the time being.
> + ; HowToConstruct = construct_in_region(_)
> )
The above code is used to record variables that contain statically
allocated data; the above XXX is unnecessary since all other sorts
of construction unification should be handled the same way at that
point.
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