Files
mercury/compiler/structure_reuse.direct.detect_garbage.m
Zoltan Somogyi 168f531867 Add new fields to the goal_info structure for region based memory management.
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.
2007-08-07 07:10:09 +00:00

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.
%-----------------------------------------------------------------------------%