mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-14 13:23:53 +00:00
Estimated hours taken: 4 Branches: main Add new fields to the goal_info structure for region based memory management. The fields are currently unused, but (a) Quan will add the code to fill them in, and then (b) I will modify the code generator to use the filled in fields. compiler/hlds_goal.m: Make the change described above. Group all the procedures that access goal_info components together. Some of the getters were predicates while some were functions, so this diff changes them all to be functions. (The setters remain predicates.) compiler/*.m: Trivial changes to conform to the change in hlds_goal.m. In simplify.m, break up a huge (800+ line) predicate into smaller pieces.
247 lines
10 KiB
Mathematica
247 lines
10 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 2006-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: structure_reuse.direct.detect_garbage.m.
|
|
% Main authors: nancy.
|
|
%
|
|
% Detect where datastructures become garbage in a given procedure: construct
|
|
% a dead cell table.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module transform_hlds.ctgc.structure_reuse.direct.detect_garbage.
|
|
:- interface.
|
|
|
|
% Using the sharing table listing all the structure sharing of all
|
|
% the known procedures, return a table of all data structures that may
|
|
% become available for reuse (i.e. cells that may become dead) of a given
|
|
% procedure goal. The table also records the reuse condition associated
|
|
% with each of the dead cells.
|
|
%
|
|
:- pred determine_dead_deconstructions(module_info::in, pred_info::in,
|
|
proc_info::in, sharing_as_table::in, hlds_goal::in,
|
|
dead_cell_table::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module libs.compiler_util.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module transform_hlds.ctgc.datastruct.
|
|
|
|
:- import_module pair.
|
|
:- import_module set.
|
|
:- import_module string.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type detect_bg_info
|
|
---> detect_bg_info(
|
|
module_info :: module_info,
|
|
pred_info :: pred_info,
|
|
proc_info :: proc_info,
|
|
sharing_table :: sharing_as_table
|
|
).
|
|
|
|
:- func detect_bg_info_init(module_info, pred_info, proc_info,
|
|
sharing_as_table) = detect_bg_info.
|
|
|
|
detect_bg_info_init(ModuleInfo, PredInfo, ProcInfo, SharingTable) =
|
|
detect_bg_info(ModuleInfo, PredInfo, ProcInfo, SharingTable).
|
|
|
|
|
|
determine_dead_deconstructions(ModuleInfo, PredInfo, ProcInfo, SharingTable,
|
|
Goal, DeadCellTable) :-
|
|
determine_dead_deconstructions(
|
|
detect_bg_info_init(ModuleInfo, PredInfo, ProcInfo, SharingTable),
|
|
Goal, DeadCellTable).
|
|
|
|
:- pred determine_dead_deconstructions(detect_bg_info::in, hlds_goal::in,
|
|
dead_cell_table::out) is det.
|
|
|
|
determine_dead_deconstructions(Background, Goal, DeadCellTable):-
|
|
% In this process we need to know the sharing at each program point,
|
|
% which boils down to reconstructing that sharing information based on the
|
|
% sharing recorded in the sharing table.
|
|
determine_dead_deconstructions_2(Background, Goal,
|
|
sharing_as_init, _, dead_cell_table_init, DeadCellTable).
|
|
|
|
% Process a procedure goal, determining the sharing at each subgoal, as
|
|
% well as constructing the table of dead cells.
|
|
%
|
|
% This means:
|
|
% - at each program point: compute sharing
|
|
% - at deconstruction unifications: check for a dead cell.
|
|
%
|
|
:- pred determine_dead_deconstructions_2(detect_bg_info::in, hlds_goal::in,
|
|
sharing_as::in, sharing_as::out, dead_cell_table::in,
|
|
dead_cell_table::out) is det.
|
|
|
|
determine_dead_deconstructions_2(Background, TopGoal, !SharingAs,
|
|
!DeadCellTable) :-
|
|
TopGoal = hlds_goal(GoalExpr, GoalInfo),
|
|
ModuleInfo = Background ^ module_info,
|
|
PredInfo = Background ^ pred_info,
|
|
ProcInfo = Background ^ proc_info,
|
|
SharingTable = Background ^ sharing_table,
|
|
(
|
|
GoalExpr = conj(_, Goals),
|
|
list.foldl2(determine_dead_deconstructions_2(Background),
|
|
Goals, !SharingAs, !DeadCellTable)
|
|
;
|
|
GoalExpr = plain_call(PredId, ProcId, ActualVars, _, _, _),
|
|
lookup_sharing_and_comb(ModuleInfo, PredInfo, ProcInfo, SharingTable,
|
|
PredId, ProcId, ActualVars, !SharingAs)
|
|
;
|
|
GoalExpr = generic_call(_GenDetails, _, _, _),
|
|
Context = goal_info_get_context(GoalInfo),
|
|
context_to_string(Context, ContextString),
|
|
!:SharingAs = sharing_as_top_sharing_accumulate(
|
|
"generic call (" ++ ContextString ++ ")", !.SharingAs)
|
|
;
|
|
GoalExpr = unify(_, _, _, Unification, _),
|
|
unification_verify_reuse(ModuleInfo, ProcInfo, GoalInfo,
|
|
Unification, program_point_init(GoalInfo), !.SharingAs,
|
|
!DeadCellTable),
|
|
!:SharingAs = add_unify_sharing(ModuleInfo, ProcInfo, Unification,
|
|
GoalInfo, !.SharingAs)
|
|
;
|
|
GoalExpr = disj(Goals),
|
|
determine_dead_deconstructions_2_disj(Background, Goals, !SharingAs,
|
|
!DeadCellTable)
|
|
;
|
|
GoalExpr = switch(_, _, Cases),
|
|
determine_dead_deconstructions_2_disj(Background,
|
|
list.map(func(C) = G :- (G = C ^ case_goal), Cases), !SharingAs,
|
|
!DeadCellTable)
|
|
;
|
|
% XXX To check and compare with the theory.
|
|
GoalExpr = negation(_Goal)
|
|
;
|
|
GoalExpr = scope(_, SubGoal),
|
|
determine_dead_deconstructions_2(Background, SubGoal, !SharingAs,
|
|
!DeadCellTable)
|
|
;
|
|
GoalExpr = if_then_else(_, IfGoal, ThenGoal, ElseGoal),
|
|
determine_dead_deconstructions_2(Background, IfGoal, !.SharingAs,
|
|
IfSharingAs, !DeadCellTable),
|
|
determine_dead_deconstructions_2(Background, ThenGoal, IfSharingAs,
|
|
ThenSharingAs, !DeadCellTable),
|
|
determine_dead_deconstructions_2(Background, ElseGoal, !.SharingAs,
|
|
ElseSharingAs, !DeadCellTable),
|
|
!:SharingAs = sharing_as_least_upper_bound(ModuleInfo, ProcInfo,
|
|
ThenSharingAs, ElseSharingAs)
|
|
;
|
|
GoalExpr = call_foreign_proc(Attributes, ForeignPredId, ForeignProcId,
|
|
_Args, _ExtraArgs, _MaybeTraceRuntimeCond, _Impl),
|
|
Context = goal_info_get_context(GoalInfo),
|
|
!:SharingAs = add_foreign_proc_sharing(ModuleInfo, ProcInfo,
|
|
proc(ForeignPredId, ForeignProcId), Attributes, Context,
|
|
!.SharingAs)
|
|
;
|
|
GoalExpr = shorthand(_),
|
|
unexpected(detect_garbage.this_file,
|
|
"determine_dead_deconstructions_2: shorthand goal.")
|
|
).
|
|
|
|
:- pred determine_dead_deconstructions_2_disj(detect_bg_info::in,
|
|
hlds_goals::in, sharing_as::in, sharing_as::out,
|
|
dead_cell_table::in, dead_cell_table::out) is det.
|
|
|
|
determine_dead_deconstructions_2_disj(Background, Goals,
|
|
!SharingAs, !DeadCellTable) :-
|
|
list.foldl2(determine_dead_deconstructions_2_disj_goal(Background,
|
|
!.SharingAs), Goals, !SharingAs, !DeadCellTable).
|
|
|
|
:- pred determine_dead_deconstructions_2_disj_goal(detect_bg_info::in,
|
|
sharing_as::in, hlds_goal::in, sharing_as::in, sharing_as::out,
|
|
dead_cell_table::in, dead_cell_table::out) is det.
|
|
|
|
determine_dead_deconstructions_2_disj_goal(Background, SharingBeforeDisj,
|
|
Goal, !SharingAs, !DeadCellTable) :-
|
|
determine_dead_deconstructions_2(Background, Goal, SharingBeforeDisj,
|
|
GoalSharing, !DeadCellTable),
|
|
!:SharingAs = sharing_as_least_upper_bound(Background ^ module_info,
|
|
Background ^ proc_info, !.SharingAs, GoalSharing).
|
|
|
|
|
|
% Verify whether the unification is a deconstruction in which the
|
|
% deconstructed data structure becomes garbage (under some reuse
|
|
% conditions).
|
|
%
|
|
% XXX Different implementation from the reuse-branch implementation.
|
|
%
|
|
:- pred unification_verify_reuse(module_info::in, proc_info::in,
|
|
hlds_goal_info::in, unification::in, program_point::in,
|
|
sharing_as::in, dead_cell_table::in, dead_cell_table::out) is det.
|
|
|
|
unification_verify_reuse(ModuleInfo, ProcInfo, GoalInfo, Unification,
|
|
PP, Sharing, !DeadCellTable):-
|
|
(
|
|
Unification = deconstruct(Var, ConsId, _, _, _, _),
|
|
LFU = goal_info_get_lfu(GoalInfo),
|
|
LBU = goal_info_get_lbu(GoalInfo),
|
|
(
|
|
% Reuse is only relevant for real constructors, with
|
|
% arity different from 0.
|
|
ConsId = cons(_, Arity),
|
|
Arity \= 0,
|
|
|
|
% Check if the top cell datastructure of Var is not live.
|
|
% If Sharing is top, then everything should automatically
|
|
% be considered live, hence no reuse possible.
|
|
\+ sharing_as_is_top(Sharing),
|
|
|
|
% Check the live set of data structures at this program point.
|
|
set.union(LFU, LBU, LU),
|
|
LU_data = set.to_sorted_list(set.map(datastruct_init, LU)),
|
|
LiveData = list.condense(
|
|
list.map(
|
|
extend_datastruct(ModuleInfo, ProcInfo, Sharing),
|
|
LU_data)),
|
|
\+ var_is_live(Var, LiveData)
|
|
->
|
|
% If all the above conditions are met, then the top
|
|
% cell data structure based on Var is dead right after
|
|
% this deconstruction, hence, may be involved with
|
|
% structure reuse.
|
|
NewCondition = reuse_condition_init(ModuleInfo,
|
|
ProcInfo, Var, LFU, LBU, Sharing),
|
|
dead_cell_table_set(PP, NewCondition, !DeadCellTable)
|
|
;
|
|
true
|
|
)
|
|
;
|
|
Unification = construct(_, _, _, _, _, _, _)
|
|
;
|
|
Unification = assign(_, _)
|
|
;
|
|
Unification = simple_test(_, _)
|
|
;
|
|
Unification = complicated_unify(_, _, _),
|
|
unexpected(detect_garbage.this_file, "unification_verify_reuse: " ++
|
|
"complicated_unify/3 encountered.")
|
|
).
|
|
|
|
:- pred var_is_live(prog_var::in, list(datastruct)::in) is semidet.
|
|
|
|
var_is_live(Var, LiveData) :-
|
|
list.member(datastruct_init(Var), LiveData).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- func this_file = string.
|
|
|
|
this_file = "structure_sharing.direct.detect_garbage.m".
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- end_module transform_hlds.ctgc.structure_reuse.direct.detect_garbage.
|
|
%-----------------------------------------------------------------------------%
|