Files
mercury/compiler/structure_reuse.direct.detect_garbage.m
Zoltan Somogyi ba93a52fe7 This diff changes a few types from being defined as equivalent to a pair
Estimated hours taken: 10
Branches: main

This diff changes a few types from being defined as equivalent to a pair
to being discriminated union types with their own function symbol. This
was motivated by an error message (one of many, but the one that broke
the camel's back) about "-" being used in an ambiguous manner. It will
reduce the number of such messages in the future, and will make compiler
data structures easier to inspect in the debugger.

The most important type changed by far is hlds_goal, whose function symbol
is now "hlds_goal". Second and third in importance are llds.instruction
(function symbol "llds_instr") and prog_item.m's item_and_context (function
symbol "item_and_context"). There are some others as well.

In several places, I rearranged predicates to factor the deconstruction of
goals into hlds_goal_expr and hlds_goal_into out of each clause into a single
point. In many places, I changed variable names that used "Goal" to refer
to just hlds_goal_exprs to use "GoalExpr" instead. I also changed variable
names that used "Item" to refer to item_and_contexts to use "ItemAndContext"
instead. This should make reading such code less confusing.

I renamed some function symbols and predicates to avoid ambiguities.

I only made one algorithmic change (at least intentionally).
In assertion.m, comparing two goals for equality now ignores goal_infos
for all kinds of goals, whereas previously it ignored them for most kinds
of goals, but for shorthand goals it was insisting on them being equal.
This seemed to me to be a bug. Pete, can you confirm this?
2007-01-06 09:23:59 +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, _, _, _),
goal_info_get_context(GoalInfo, Context),
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),
goal_info_get_context(GoalInfo, Context),
!: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.
%-----------------------------------------------------------------------------%