Files
mercury/compiler/closure_analysis.m
Zoltan Somogyi 04dec8c205 Carve vartypes.m, prog_detism.m and prog_rename.m out of prog_data.m.
Besides defining most of the types representing the smaller parts of
parse trees (parts smaller than items), prog_data.m also has many utility
predicates that operate on values of these types. Carve the three substantial
clusters of predicates out of prog_data.m, and move them into their own
modules, which are each imported by fewer modules than prog_data.m itself.

compiler/vartypes.m:
    New module containing the vartypes type and the predicates that operate
    on it. The new module has *much* better cohesion than the old prog_data.m.

    The vartypes type does not appear in any parse tree; it is used only
    in the HLDS. So make vartypes.m part of the hlds.m package, not
    parse_tree.m.

    Move three predicates that perform renamings and substitutions on vartypes
    here from prog_type_subst.m, since the latter is part of the parse_tree.m
    package, and thus doesn't have access to hlds.vartypes. Make private
    the service predicate that these three moved predicates used to rely on,
    since it has no other callers.

compiler/prog_detism.m:
    New module containing utility predicates that operate on determinisms
    and determinism components.

compiler/prog_rename.m:
    New module containing utility predicates that rename variables in
    various data structures.

compiler/prog_data.m:
    Remove the stuff now in the three new modules.

compiler/prog_type_subst.m:
    Remove the three predicates now in vartypes.m.

compiler/mercury_to_mercury.m:
    Delete an unneded predicate, which was the only part of this module
    that referred to vartypes.

compiler/prog_type.m:
compiler/builtin_lib_types.m:
compiler/type_util.m:
    Move some utility predicates that refer to vartypes from prog_type.m
    and builtin_lib_types.m (both part of parse_tree.m) to type_util.m
    (part of check_hlds.m).

compiler/parse_tree.m:
compiler/hlds.m:
compiler/notes/compiler_design.html:
    Mention the new modules.

compiler/accumulator.m:
compiler/add_class.m:
compiler/add_clause.m:
compiler/add_foreign_proc.m:
compiler/add_heap_ops.m:
compiler/add_pragma_type_spec.m:
compiler/add_pred.m:
compiler/add_trail_ops.m:
compiler/arg_info.m:
compiler/bytecode_gen.m:
compiler/call_gen.m:
compiler/clause_to_proc.m:
compiler/closure_analysis.m:
compiler/code_info.m:
compiler/code_loc_dep.m:
compiler/common.m:
compiler/complexity.m:
compiler/const_prop.m:
compiler/constraint.m:
compiler/continuation_info.m:
compiler/coverage_profiling.m:
compiler/cse_detection.m:
compiler/ctgc.datastruct.m:
compiler/ctgc.util.m:
compiler/deep_profiling.m:
compiler/deforest.m:
compiler/delay_construct.m:
compiler/delay_partial_inst.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_code.m:
compiler/follow_vars.m:
compiler/format_call.m:
compiler/goal_expr_to_goal.m:
compiler/goal_path.m:
compiler/goal_store.m:
compiler/goal_util.m:
compiler/headvar_names.m:
compiler/hhf.m:
compiler/higher_order.m:
compiler/hlds_clauses.m:
compiler/hlds_goal.m:
compiler/hlds_llds.m:
compiler/hlds_out_goal.m:
compiler/hlds_out_module.m:
compiler/hlds_out_pred.m:
compiler/hlds_pred.m:
compiler/hlds_rtti.m:
compiler/inlining.m:
compiler/inst_util.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/make_goal.m:
compiler/mark_tail_calls.m:
compiler/ml_accurate_gc.m:
compiler/ml_code_gen.m:
compiler/ml_code_util.m:
compiler/ml_disj_gen.m:
compiler/ml_gen_info.m:
compiler/ml_lookup_switch.m:
compiler/ml_proc_gen.m:
compiler/ml_unify_gen.m:
compiler/mode_constraints.m:
compiler/mode_info.m:
compiler/mode_util.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_rep.m:
compiler/prop_mode_constraints.m:
compiler/purity.m:
compiler/qual_info.m:
compiler/quantification.m:
compiler/rbmm.points_to_graph.m:
compiler/rbmm.points_to_info.m:
compiler/rbmm.region_liveness_info.m:
compiler/rbmm.region_transformation.m:
compiler/saved_vars.m:
compiler/set_of_var.m:
compiler/simplify_goal_call.m:
compiler/simplify_goal_conj.m:
compiler/simplify_goal_disj.m:
compiler/simplify_goal_ite.m:
compiler/simplify_goal_scope.m:
compiler/simplify_goal_switch.m:
compiler/simplify_goal_unify.m:
compiler/simplify_info.m:
compiler/simplify_proc.m:
compiler/size_prof.m:
compiler/ssdebug.m:
compiler/stack_alloc.m:
compiler/stack_layout.m:
compiler/stack_opt.m:
compiler/stm_expand.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_reuse.lbu.m:
compiler/structure_reuse.lfu.m:
compiler/structure_sharing.analysis.m:
compiler/structure_sharing.domain.m:
compiler/switch_detection.m:
compiler/table_gen.m:
compiler/tabling_analysis.m:
compiler/term_constr_build.m:
compiler/term_constr_initial.m:
compiler/term_constr_util.m:
compiler/term_pass1.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_assign.m:
compiler/type_constraints.m:
compiler/typecheck.m:
compiler/typecheck_errors.m:
compiler/unify_gen.m:
compiler/unify_proc.m:
compiler/unique_modes.m:
compiler/unneeded_code.m:
compiler/untupling.m:
compiler/unused_args.m:
compiler/var_locn.m:
    Conform to the above changes, mostly by importing some of the
    three new modules as well as, or instead of, prog_data.m.
2015-08-09 19:02:12 +10:00

506 lines
20 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 2005-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: closure_analysis.m
% Main author: juliensf
%
% Perform local closure analysis on procedures. This involves tracking
% the possible values that a higher-order variable can take within a
% procedure. We attach this information to places where knowing the
% possible values of a higher-order call may be useful.
%
% This is similar to the analysis done by higher-order specialization, except
% that here, we do care if a higher-order variable can take multiple values.
%
%-----------------------------------------------------------------------------%
:- module transform_hlds.closure_analysis.
:- interface.
:- import_module hlds.hlds_module.
:- import_module io.
:- pred closure_analyse_module(module_info::in, module_info::out,
io::di, io::uo) is det.
%----------------------------------------------------------------------------%
%----------------------------------------------------------------------------%
:- implementation.
:- import_module check_hlds.mode_util.
:- import_module hlds.hlds_goal.
:- import_module hlds.hlds_pred.
:- import_module hlds.passes_aux.
:- import_module hlds.vartypes.
:- import_module libs.globals.
:- import_module libs.options.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.prog_out.
:- import_module parse_tree.prog_type.
:- import_module parse_tree.set_of_var.
:- import_module transform_hlds.dependency_graph.
:- import_module assoc_list.
:- import_module bool.
:- import_module list.
:- import_module map.
:- import_module maybe.
:- import_module pair.
:- import_module require.
:- import_module set.
:- import_module string.
:- import_module varset.
%----------------------------------------------------------------------------%
closure_analyse_module(!ModuleInfo, !IO) :-
% XXX At the moment it is not necessary to do this on a per-SCC basis,
% since the analysis is only procedure-local, but we would eventually
% like to extend it.
module_info_get_globals(!.ModuleInfo, Globals),
globals.lookup_bool_option(Globals, debug_closure, Debug),
module_info_ensure_dependency_info(!ModuleInfo),
module_info_dependency_info(!.ModuleInfo, DepInfo),
hlds_dependency_info_get_dependency_ordering(DepInfo, SCCs),
list.foldl2(closure_analyse_scc(Debug), SCCs, !ModuleInfo, !IO).
%----------------------------------------------------------------------------%
%
% Perform closure analysis on an SCC.
%
:- pred closure_analyse_scc(bool::in, list(pred_proc_id)::in,
module_info::in, module_info::out, io::di, io::uo) is det.
closure_analyse_scc(Debug, SCC, !ModuleInfo, !IO) :-
list.foldl2(closure_analyse_proc(Debug), SCC, !ModuleInfo, !IO).
%----------------------------------------------------------------------------%
% This type represents the possible values of a higher-order valued
% variable.
%
:- type closure_values
---> unknown
% The higher-order variable may be bound to something,
% but we don't know what it is.
; partial(set(pred_proc_id))
% The higher-order variable may be bound to these values,
% or it may be bound to something else we don't know about.
% (This is intended to be useful in producing error messages
% for the termination analysis; if one of the higher-order values
% is definitely non-terminating, we can certainly let the user
% know about it.)
; exclusive(set(pred_proc_id)).
% The higher-order variable can be bound only to one of the
% procedures identified by this set.
% We attach a closure_info to each goal where it may be of interest;
% at the moment calls and generic_calls.
%
:- type closure_info == map(prog_var, closure_values).
%----------------------------------------------------------------------------%
:- func closure_info_init(module_info, vartypes, prog_vars, list(mer_mode))
= closure_info.
closure_info_init(ModuleInfo, VarTypes, HeadVars, ArgModes) = ClosureInfo :-
partition_arguments(ModuleInfo, VarTypes, HeadVars, ArgModes,
set_of_var.init, Inputs0, set_of_var.init, _Outputs),
Inputs = set_of_var.filter(var_has_ho_type(VarTypes), Inputs0),
set_of_var.fold(insert_unknown, Inputs, map.init, ClosureInfo).
% Succeeds iff the given variable has a higher-order type.
%
:- pred var_has_ho_type(vartypes::in, prog_var::in) is semidet.
var_has_ho_type(VarTypes, Var) :-
lookup_var_type(VarTypes, Var, Type),
type_is_higher_order(Type).
% Insert the given prog_var into the closure_info, and set the
% possible values to unknown.
%
:- pred insert_unknown(prog_var::in, closure_info::in, closure_info::out)
is det.
insert_unknown(Var, !ClosureInfo) :-
map.det_insert(Var, unknown, !ClosureInfo).
%----------------------------------------------------------------------------%
%
% Perform local closure analysis on a procedure.
%
:- pred closure_analyse_proc(bool::in, pred_proc_id::in,
module_info::in, module_info::out, io::di, io::uo) is det.
closure_analyse_proc(Debug, PPId, !ModuleInfo, !IO) :-
module_info_pred_proc_info(!.ModuleInfo, PPId, PredInfo, ProcInfo0),
proc_info_get_headvars(ProcInfo0, HeadVars),
proc_info_get_vartypes(ProcInfo0, VarTypes),
proc_info_get_argmodes(ProcInfo0, ArgModes),
ClosureInfo0 = closure_info_init(!.ModuleInfo, VarTypes, HeadVars,
ArgModes),
write_proc_progress_message("% Analysing closures in ", PPId, !.ModuleInfo,
!IO),
proc_info_get_goal(ProcInfo0, Body0),
closure_analyse_goal(VarTypes, !.ModuleInfo, Body0, Body,
ClosureInfo0, _ClosureInfo),
(
Debug = yes,
proc_info_get_varset(ProcInfo, Varset),
dump_closure_info(Varset, Body, !IO),
io.flush_output(!IO)
;
Debug = no
),
proc_info_set_goal(Body, ProcInfo0, ProcInfo),
module_info_set_pred_proc_info(PPId, PredInfo, ProcInfo, !ModuleInfo).
%-----------------------------------------------------------------------------%
%
% Track higher-order values through goals.
%
:- pred closure_analyse_goal(vartypes::in, module_info::in,
hlds_goal::in, hlds_goal::out, closure_info::in, closure_info::out) is det.
closure_analyse_goal(VarTypes, ModuleInfo, Goal0, Goal, !ClosureInfo) :-
Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
(
GoalExpr0 = conj(ConjType, Goals0),
list.map_foldl(closure_analyse_goal(VarTypes, ModuleInfo),
Goals0, Goals, !ClosureInfo),
GoalExpr = conj(ConjType, Goals),
Goal = hlds_goal(GoalExpr, GoalInfo0)
;
GoalExpr0 = plain_call(CallPredId, CallProcId, CallArgs, _, _, _),
% Look for any higher-order arguments and divide them
% into sets of input and output arguments.
module_info_pred_proc_info(ModuleInfo, CallPredId, CallProcId,
_CallPredInfo, CallProcInfo),
proc_info_get_argmodes(CallProcInfo, CallArgModes),
% NOTE: We construct sets of arguments, rather than lists,
% in case there are duplicate arguments.
partition_arguments(ModuleInfo, VarTypes, CallArgs, CallArgModes,
set_of_var.init, InputArgs, set_of_var.init, OutputArgs),
% Update the goal_info to include any information about the
% values of higher-order valued variables.
AddValues = (pred(Var::in, !.ValueMap::in, !:ValueMap::out) is det :-
% The closure_info won't yet contain any information about
% higher-order outputs from this call.
( map.search(!.ClosureInfo, Var, PossibleValues) ->
(
PossibleValues = unknown
;
PossibleValues = partial(_)
;
PossibleValues = exclusive(KnownValues),
map.det_insert(Var, KnownValues, !ValueMap)
)
;
true
)
),
set_of_var.fold(AddValues, InputArgs, map.init, Values),
goal_info_set_ho_values(Values, GoalInfo0, GoalInfo),
% Insert any information about higher-order outputs from this call
% into the closure_info.
set_of_var.fold(insert_unknown, OutputArgs, !ClosureInfo),
Goal = hlds_goal(GoalExpr0, GoalInfo)
;
GoalExpr0 = generic_call(Details, GCallArgs, GCallModes, _, _),
partition_arguments(ModuleInfo, VarTypes, GCallArgs, GCallModes,
set_of_var.init, InputArgs0, set_of_var.init, OutputArgs),
% For higher-order calls we need to make sure that the actual
% higher-order variable being called is also considered (it will
% typically be the variable of interest). This variable is not included
% in 'GCallArgs' so we need to include in the set of input argument
% separately.
( Details = higher_order(CalledClosure0, _, _, _) ->
set_of_var.insert(CalledClosure0, InputArgs0, InputArgs)
;
InputArgs = InputArgs0
),
AddValues = (pred(Var::in, !.ValueMap::in, !:ValueMap::out) is det :-
% The closure_info won't yet contain any information about
% higher-order outputs from this call.
( map.search(!.ClosureInfo, Var, PossibleValues) ->
(
PossibleValues = unknown
;
PossibleValues = partial(_)
;
PossibleValues = exclusive(KnownValues),
map.det_insert(Var, KnownValues, !ValueMap)
)
;
true
)
),
set_of_var.fold(AddValues, InputArgs, map.init, Values),
goal_info_set_ho_values(Values, GoalInfo0, GoalInfo),
% Insert any information about higher-order outputs from this call
% into the closure_info.
set_of_var.fold(insert_unknown, OutputArgs, !ClosureInfo),
Goal = hlds_goal(GoalExpr0, GoalInfo)
;
GoalExpr0 = switch(SwitchVar, SwitchCanFail, Cases0),
ProcessCase = (func(Case0) = Case - CaseInfo :-
Case0 = case(MainConsId, OtherConsIds, CaseGoal0),
closure_analyse_goal(VarTypes, ModuleInfo, CaseGoal0, CaseGoal,
!.ClosureInfo, CaseInfo),
Case = case(MainConsId, OtherConsIds, CaseGoal)
),
CasesAndInfos = list.map(ProcessCase, Cases0),
assoc_list.keys_and_values(CasesAndInfos, Cases, CasesInfo),
list.foldl(merge_closure_infos, CasesInfo, map.init, !:ClosureInfo),
GoalExpr = switch(SwitchVar, SwitchCanFail, Cases),
Goal = hlds_goal(GoalExpr, GoalInfo0)
;
GoalExpr0 = unify(_, _, _, Unification, _),
(
Unification = construct(LHS, RHS, _, _, _, _, _),
(
RHS = closure_cons(ShroudedPPId, EvalMethod),
EvalMethod = lambda_normal
->
PPId = unshroud_pred_proc_id(ShroudedPPId),
HO_Value = set.make_singleton_set(PPId),
map.det_insert(LHS, exclusive(HO_Value), !ClosureInfo)
;
true
)
;
Unification = deconstruct(_, _, Args, _, _, _),
% XXX We don't currently support tracking the values of closures
% that are stored in data structures.
HO_Args = list.filter(var_has_ho_type(VarTypes), Args),
list.foldl(insert_unknown, HO_Args, !ClosureInfo)
;
Unification = assign(LHS, RHS),
( var_has_ho_type(VarTypes, LHS) ->
% Sanity check: make sure the rhs is also a higher-order
% variable.
( var_has_ho_type(VarTypes, RHS) ->
true
;
unexpected($module, $pred, "not a higher-order var")
),
Values = map.lookup(!.ClosureInfo, RHS),
map.det_insert(LHS, Values, !ClosureInfo)
;
true
)
;
Unification = simple_test(_, _)
;
Unification = complicated_unify(_, _, _)
),
Goal = Goal0
;
GoalExpr0 = disj(Goals0),
ProcessDisjunct = (func(Disjunct0) = DisjunctResult :-
closure_analyse_goal(VarTypes, ModuleInfo, Disjunct0, Disjunct,
!.ClosureInfo, ClosureInfoForDisjunct),
DisjunctResult = Disjunct - ClosureInfoForDisjunct
),
DisjunctsAndInfos = list.map(ProcessDisjunct, Goals0),
assoc_list.keys_and_values(DisjunctsAndInfos, Goals, DisjunctsInfo),
list.foldl(merge_closure_infos, DisjunctsInfo,
map.init, !:ClosureInfo),
GoalExpr = disj(Goals),
Goal = hlds_goal(GoalExpr, GoalInfo0)
;
GoalExpr0 = negation(NegatedGoal0),
closure_analyse_goal(VarTypes, ModuleInfo, NegatedGoal0, NegatedGoal,
!.ClosureInfo, _),
GoalExpr = negation(NegatedGoal),
Goal = hlds_goal(GoalExpr, GoalInfo0)
;
GoalExpr0 = scope(Reason, SubGoal0),
(
Reason = from_ground_term(_, FGT),
( FGT = from_ground_term_construct
; FGT = from_ground_term_deconstruct
)
->
SubGoal = SubGoal0
;
closure_analyse_goal(VarTypes, ModuleInfo,
SubGoal0, SubGoal, !ClosureInfo)
),
GoalExpr = scope(Reason, SubGoal),
Goal = hlds_goal(GoalExpr, GoalInfo0)
;
GoalExpr0 = if_then_else(ExistQVars, Cond0, Then0, Else0),
closure_analyse_goal(VarTypes, ModuleInfo, Cond0, Cond,
!.ClosureInfo, CondInfo),
closure_analyse_goal(VarTypes, ModuleInfo, Then0, Then,
CondInfo, CondThenInfo),
closure_analyse_goal(VarTypes, ModuleInfo, Else0, Else,
!.ClosureInfo, ElseInfo),
map.union(merge_closure_values, CondThenInfo, ElseInfo, !:ClosureInfo),
GoalExpr = if_then_else(ExistQVars, Cond, Then, Else),
Goal = hlds_goal(GoalExpr, GoalInfo0)
;
GoalExpr0 = call_foreign_proc(_, _, _, Args, _ExtraArgs, _, _),
% XXX We may eventually want to annotate foreign_procs with
% clousure_infos as well. It isn't useful at the moment however.
ForeignHOArgs = (pred(Arg::in, Out::out) is semidet :-
Arg = foreign_arg(Var, NameMode, Type, _BoxPolicy),
% A 'no' here means that the foreign argument is unused.
NameMode = yes(_ - Mode),
mode_util.mode_is_output(ModuleInfo, Mode),
type_is_higher_order(Type),
Out = Var - unknown
),
list.filter_map(ForeignHOArgs, Args, OutputForeignHOArgs),
map.det_insert_from_assoc_list(OutputForeignHOArgs, !ClosureInfo),
Goal = Goal0
;
GoalExpr0 = shorthand(_),
unexpected($module, $pred, "shorthand")
).
%----------------------------------------------------------------------------%
:- pred partition_arguments(module_info::in, vartypes::in,
prog_vars::in, list(mer_mode)::in,
set_of_progvar::in, set_of_progvar::out,
set_of_progvar::in, set_of_progvar::out) is det.
partition_arguments(_, _, [], [], !Inputs, !Outputs).
partition_arguments(_, _, [_|_], [], _, _, _, _) :-
unexpected($module, $pred, "unequal length lists.").
partition_arguments(_, _, [], [_|_], _, _, _, _) :-
unexpected($module, $pred, "unequal length lists.").
partition_arguments(ModuleInfo, VarTypes, [ Var | Vars ], [ Mode | Modes ],
!Inputs, !Outputs) :-
( var_has_ho_type(VarTypes, Var) ->
( mode_is_input(ModuleInfo, Mode) ->
set_of_var.insert(Var, !Inputs)
; mode_is_output(ModuleInfo, Mode) ->
set_of_var.insert(Var, !Outputs)
;
true
)
;
true
),
partition_arguments(ModuleInfo, VarTypes, Vars, Modes, !Inputs, !Outputs).
:- pred merge_closure_infos(closure_info::in, closure_info::in,
closure_info::out) is det.
merge_closure_infos(A, B, C) :-
map.union(merge_closure_values, A, B, C).
:- pred merge_closure_values(closure_values::in, closure_values::in,
closure_values::out) is det.
merge_closure_values(unknown, unknown, unknown).
merge_closure_values(unknown, partial(A), partial(A)).
merge_closure_values(unknown, exclusive(A), partial(A)).
merge_closure_values(partial(A), unknown, partial(A)).
merge_closure_values(partial(A), partial(B), partial(A `set.union` B)).
merge_closure_values(partial(A), exclusive(B), partial(A `set.union` B)).
merge_closure_values(exclusive(A), unknown, partial(A)).
merge_closure_values(exclusive(A), partial(B), partial(A `set.union` B)).
merge_closure_values(exclusive(A), exclusive(B), exclusive(A `set.union` B)).
%----------------------------------------------------------------------------%
%
% Debugging code, used if the '--debug-closure' option is given.
%
:- pred dump_closure_info(prog_varset::in, hlds_goal::in,
io::di, io::uo) is det.
dump_closure_info(Varset, Goal, !IO) :-
Goal = hlds_goal(GoalExpr, GoalInfo),
dump_closure_info_expr(Varset, GoalExpr, GoalInfo, !IO).
:- pred dump_closure_info_expr(prog_varset::in, hlds_goal_expr::in,
hlds_goal_info::in, io::di, io::uo) is det.
dump_closure_info_expr(Varset, conj(_ConjType, Goals), _, !IO) :-
list.foldl(dump_closure_info(Varset), Goals, !IO).
dump_closure_info_expr(Varset, plain_call(_,_,_,_,_,_), GoalInfo, !IO) :-
dump_ho_values(GoalInfo, Varset, !IO).
dump_closure_info_expr(Varset, generic_call(_,_,_,_,_), GoalInfo, !IO) :-
dump_ho_values(GoalInfo, Varset, !IO).
dump_closure_info_expr(Varset, scope(_, Goal), _, !IO) :-
dump_closure_info(Varset, Goal, !IO).
dump_closure_info_expr(Varset, switch(_, _, Cases), _, !IO) :-
CaseToGoal = (func(case(_, _, Goal)) = Goal),
Goals = list.map(CaseToGoal, Cases),
list.foldl(dump_closure_info(Varset), Goals, !IO).
dump_closure_info_expr(Varset, if_then_else(_, Cond, Then, Else), _, !IO) :-
list.foldl(dump_closure_info(Varset), [Cond, Then, Else], !IO).
dump_closure_info_expr(_, unify(_,_,_,_,_), _, !IO).
dump_closure_info_expr(Varset, negation(Goal), _, !IO) :-
dump_closure_info(Varset, Goal, !IO).
dump_closure_info_expr(_, call_foreign_proc(_, _, _, _, _, _, _), _, !IO).
dump_closure_info_expr(Varset, disj(Goals), _, !IO) :-
list.foldl(dump_closure_info(Varset), Goals, !IO).
dump_closure_info_expr(_, shorthand(_), _, _, _) :-
unexpected($module, $pred, "shorthand").
:- pred dump_ho_values(hlds_goal_info::in, prog_varset::in,
io::di, io::uo) is det.
dump_ho_values(GoalInfo, Varset, !IO) :-
HO_Values = goal_info_get_ho_values(GoalInfo),
( map.is_empty(HO_Values) ->
true
;
prog_out.write_context(goal_info_get_context(GoalInfo), !IO),
io.nl(!IO),
map.foldl(dump_ho_value(Varset), HO_Values, !IO)
).
:- pred dump_ho_value(prog_varset::in, prog_var::in, set(pred_proc_id)::in,
io::di, io::uo) is det.
dump_ho_value(Varset, ProgVar, Values, !IO) :-
VarName = varset.lookup_name(Varset, ProgVar),
io.format("%s =\n", [s(VarName)], !IO),
WritePPIds = (pred(PPId::in, !.IO::di, !:IO::uo) is det :-
io.write_string("\t", !IO),
io.write(PPId, !IO),
io.nl(!IO)
),
set.fold(WritePPIds, Values, !IO).
%----------------------------------------------------------------------------%
:- end_module transform_hlds.closure_analysis.
%----------------------------------------------------------------------------%