mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-14 05:12:33 +00:00
Estimated hours taken: 4 Branches: main compiler/prog_data.m: Make vartypes an abstract data type, in preparation for exploring better representations for it. compiler/mode_util.m: Provide two different versions of a predicate. The generic version continues to use map lookups. The other version knows it works on prog_vars, so it can use the abstract operations on them provided by prog_data.m. compiler/accumulator.m: compiler/add_class.m: compiler/add_heap_ops.m: compiler/add_pragma.m: compiler/add_pred.m: compiler/add_trail_ops.m: compiler/arg_info.m: compiler/builtin_lib_types.m: compiler/bytecode_gen.m: compiler/call_gen.m: compiler/clause_to_proc.m: compiler/closure_analysis.m: compiler/code_info.m: compiler/common.m: compiler/complexity.m: compiler/const_prop.m: compiler/constraint.m: compiler/continuation_info.m: compiler/cse_detection.m: compiler/ctgc.datastruct.m: compiler/ctgc.util.m: compiler/deep_profiling.m: compiler/deforest.m: compiler/dep_par_conj.m: compiler/det_analysis.m: compiler/det_report.m: compiler/det_util.m: compiler/disj_gen.m: compiler/equiv_type_hlds.m: compiler/erl_call_gen.m: compiler/erl_code_gen.m: compiler/erl_code_util.m: compiler/exception_analysis.m: compiler/float_regs.m: compiler/follow_vars.m: compiler/format_call.m: compiler/goal_path.m: compiler/goal_util.m: compiler/hhf.m: compiler/higher_order.m: compiler/hlds_clauses.m: compiler/hlds_goal.m: compiler/hlds_out_goal.m: compiler/hlds_out_pred.m: compiler/hlds_pred.m: compiler/hlds_rtti.m: compiler/inlining.m: compiler/instmap.m: compiler/intermod.m: compiler/interval.m: compiler/lambda.m: compiler/lco.m: compiler/live_vars.m: compiler/liveness.m: compiler/lookup_switch.m: compiler/mercury_to_mercury.m: compiler/ml_accurate_gc.m: compiler/ml_closure_gen.m: compiler/ml_code_gen.m: compiler/ml_code_util.m: compiler/ml_disj_gen.m: compiler/ml_lookup_switch.m: compiler/ml_proc_gen.m: compiler/ml_unify_gen.m: compiler/mode_info.m: compiler/modecheck_call.m: compiler/modecheck_conj.m: compiler/modecheck_goal.m: compiler/modecheck_unify.m: compiler/modecheck_util.m: compiler/modes.m: compiler/par_loop_control.m: compiler/pd_info.m: compiler/pd_util.m: compiler/polymorphism.m: compiler/post_typecheck.m: compiler/prog_type_subst.m: compiler/prop_mode_constraints.m: compiler/purity.m: compiler/qual_info.m: compiler/rbmm.points_to_info.m: compiler/rbmm.region_liveness_info.m: compiler/rbmm.region_transformation.m: compiler/saved_vars.m: compiler/simplify.m: compiler/size_prof.m: compiler/ssdebug.m: compiler/stack_alloc.m: compiler/stack_opt.m: compiler/store_alloc.m: compiler/structure_reuse.analysis.m: compiler/structure_reuse.direct.choose_reuse.m: compiler/structure_reuse.direct.detect_garbage.m: compiler/structure_reuse.indirect.m: compiler/structure_sharing.analysis.m: compiler/structure_sharing.domain.m: compiler/switch_detection.m: compiler/table_gen.m: compiler/term_constr_build.m: compiler/term_constr_util.m: compiler/term_traversal.m: compiler/term_util.m: compiler/trace_gen.m: compiler/trailing_analysis.m: compiler/try_expand.m: compiler/tupling.m: compiler/type_constraints.m: compiler/type_util.m: compiler/typecheck.m: compiler/typecheck_errors.m: compiler/typecheck_info.m: compiler/unify_gen.m: compiler/unify_proc.m: compiler/unique_modes.m: compiler/untupling.m: compiler/unused_args.m: compiler/var_locn.m: Conform to the above. compiler/prog_type.m: compiler/rbmm.points_to_graph.m: Conform to the above. Move some comments where they belong. compiler/stm_expand.m: Conform to the above. Do not export a predicate that is not used outside this module. Disable some debugging output unless it is asked for. Remove unnecessary prefixes on variable names. library/version_array.m: Instead writing code for field access lookalike functions and defining lookup, set etc in terms of them, write code for lookup, set etc, and define the field access lookalike functions in terms of them. Change argument orders of some internal predicates to be more state variable friendly. Fix typos in comments. tests/hard_coded/version_array_test.exp: Conform to the change to version_array.m.
322 lines
12 KiB
Mathematica
322 lines
12 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 2006-2012 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.
|
|
|
|
:- import_module hlds.hlds_goal.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% 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 check_hlds.type_util.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.prog_out.
|
|
:- import_module parse_tree.set_of_var.
|
|
:- import_module transform_hlds.ctgc.datastruct.
|
|
:- import_module transform_hlds.ctgc.livedata.
|
|
|
|
:- import_module bool.
|
|
:- import_module io.
|
|
:- import_module require.
|
|
:- import_module string.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type detect_bg_info
|
|
---> detect_bg_info(
|
|
dbgi_module_info :: module_info,
|
|
dbgi_pred_info :: pred_info,
|
|
dbgi_proc_info :: proc_info,
|
|
dbgi_sharing_table :: sharing_as_table,
|
|
dbgi_very_verbose :: bool
|
|
).
|
|
|
|
:- 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) = BG :-
|
|
module_info_get_globals(ModuleInfo, Globals),
|
|
globals.lookup_bool_option(Globals, very_verbose, VeryVerbose),
|
|
BG = detect_bg_info(ModuleInfo, PredInfo, ProcInfo, SharingTable,
|
|
VeryVerbose).
|
|
|
|
determine_dead_deconstructions(ModuleInfo, PredInfo, ProcInfo, SharingTable,
|
|
Goal, DeadCellTable) :-
|
|
Background = detect_bg_info_init(ModuleInfo, PredInfo, ProcInfo,
|
|
SharingTable),
|
|
% 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),
|
|
|
|
% Add a newline after the "progress dots".
|
|
VeryVerbose = Background ^ dbgi_very_verbose,
|
|
(
|
|
VeryVerbose = yes,
|
|
trace [io(!IO)] (
|
|
io.nl(!IO)
|
|
)
|
|
;
|
|
VeryVerbose = no
|
|
).
|
|
|
|
% 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 ^ dbgi_module_info,
|
|
PredInfo = Background ^ dbgi_pred_info,
|
|
ProcInfo = Background ^ dbgi_proc_info,
|
|
SharingTable = Background ^ dbgi_sharing_table,
|
|
(
|
|
GoalExpr = conj(_, Goals),
|
|
list.foldl2(determine_dead_deconstructions_2_with_progress(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, CallArgs, Modes, _MaybeArgRegs,
|
|
_Detism),
|
|
determine_dead_deconstructions_generic_call(ModuleInfo, ProcInfo,
|
|
GenDetails, CallArgs, Modes, GoalInfo, !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(Reason, SubGoal),
|
|
( Reason = from_ground_term(_, from_ground_term_construct) ->
|
|
true
|
|
;
|
|
determine_dead_deconstructions_2(Background, SubGoal, !SharingAs,
|
|
!DeadCellTable)
|
|
)
|
|
;
|
|
GoalExpr = if_then_else(_, CondGoal, ThenGoal, ElseGoal),
|
|
determine_dead_deconstructions_2(Background, CondGoal, !.SharingAs,
|
|
CondSharingAs, !DeadCellTable),
|
|
determine_dead_deconstructions_2(Background, ThenGoal, CondSharingAs,
|
|
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),
|
|
ForeignPPId = proc(ForeignPredId, ForeignProcId),
|
|
Context = goal_info_get_context(GoalInfo),
|
|
add_foreign_proc_sharing(ModuleInfo, PredInfo, ProcInfo, ForeignPPId,
|
|
Attributes, Args, Context, !SharingAs)
|
|
;
|
|
GoalExpr = shorthand(_),
|
|
% These should have been expanded out by now.
|
|
unexpected($module, $pred, "shorthand")
|
|
).
|
|
|
|
:- pred determine_dead_deconstructions_2_with_progress(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_with_progress(Background, TopGoal,
|
|
!SharingAs, !DeadCellTable) :-
|
|
VeryVerbose = Background ^ dbgi_very_verbose,
|
|
(
|
|
VeryVerbose = yes,
|
|
trace [io(!IO)] (
|
|
io.write_char('.', !IO),
|
|
io.flush_output(!IO)
|
|
)
|
|
;
|
|
VeryVerbose = no
|
|
),
|
|
determine_dead_deconstructions_2(Background, TopGoal, !SharingAs,
|
|
!DeadCellTable).
|
|
|
|
:- 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 ^ dbgi_module_info,
|
|
Background ^ dbgi_proc_info, !.SharingAs, GoalSharing).
|
|
|
|
:- pred determine_dead_deconstructions_generic_call(module_info::in,
|
|
proc_info::in, generic_call::in, prog_vars::in, list(mer_mode)::in,
|
|
hlds_goal_info::in, sharing_as::in, sharing_as::out) is det.
|
|
|
|
determine_dead_deconstructions_generic_call(ModuleInfo, ProcInfo,
|
|
GenDetails, CallArgs, Modes, GoalInfo, !SharingAs) :-
|
|
(
|
|
( GenDetails = higher_order(_, _, _, _)
|
|
; GenDetails = class_method(_, _, _, _)
|
|
),
|
|
proc_info_get_vartypes(ProcInfo, CallerVarTypes),
|
|
lookup_var_types(CallerVarTypes, CallArgs, ActualTypes),
|
|
(
|
|
bottom_sharing_is_safe_approximation_by_args(ModuleInfo, Modes,
|
|
ActualTypes)
|
|
->
|
|
SetToTop = no
|
|
;
|
|
SetToTop = yes
|
|
)
|
|
;
|
|
( GenDetails = event_call(_) % XXX too conservative
|
|
; GenDetails = cast(_)
|
|
),
|
|
SetToTop = yes
|
|
),
|
|
(
|
|
SetToTop = yes,
|
|
Context = goal_info_get_context(GoalInfo),
|
|
context_to_string(Context, ContextString),
|
|
!:SharingAs = sharing_as_top_sharing_accumulate(
|
|
top_cannot_improve("generic call (" ++ ContextString ++ ")"),
|
|
!.SharingAs)
|
|
;
|
|
SetToTop = no
|
|
).
|
|
|
|
% 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 nonzero
|
|
% arities.
|
|
ConsId = cons(_, Arity, _),
|
|
Arity \= 0,
|
|
|
|
% No-tag values don't have a cell to reuse.
|
|
proc_info_get_vartypes(ProcInfo, VarTypes),
|
|
lookup_var_type(VarTypes, Var, Type),
|
|
\+ type_is_no_tag_type(ModuleInfo, Type),
|
|
|
|
% 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.
|
|
var_not_live(ModuleInfo, ProcInfo, GoalInfo, Sharing, Var)
|
|
->
|
|
% If all the above conditions are met, then the top cell
|
|
% data structure based on Var is dead right after this
|
|
% deconstruction, which means it may be reused.
|
|
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($module, $pred, "complicated_unify")
|
|
).
|
|
|
|
:- pred var_not_live(module_info::in, proc_info::in, hlds_goal_info::in,
|
|
sharing_as::in, prog_var::in) is semidet.
|
|
|
|
var_not_live(ModuleInfo, ProcInfo, GoalInfo, Sharing, Var) :-
|
|
LiveData = livedata_init_at_goal(ModuleInfo, ProcInfo, GoalInfo, Sharing),
|
|
nodes_are_not_live(ModuleInfo, ProcInfo, [datastruct_init(Var)], LiveData,
|
|
NotLive),
|
|
(
|
|
NotLive = nodes_are_live([])
|
|
;
|
|
( NotLive = nodes_all_live
|
|
; NotLive = nodes_are_live([_ | _])
|
|
),
|
|
fail
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- end_module transform_hlds.ctgc.structure_reuse.direct.detect_garbage.
|
|
%-----------------------------------------------------------------------------%
|