mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 17:33:38 +00:00
Class and instance definitions both contain lists of methods,
predicates and/or functions, that each have one or more procedures.
Until now, we represented the methods in class and instance definitions
as lists of nothing more than pred_proc_ids. This fact complicated
several operations,
- partly because there was no simple way to tell which procedures
were part of the same predicate or function, and
- partly because the order of the list is important (we identify
each method procedure in our equivalent of vtables with a number,
which is simply the procedure's position in this list), but there was
absolutely no information about recorded about this.
This diff therefore replaces the lists of pred_proc_ids with lists of
method_infos. Each method_info contains
- the method procedure number, i.e. the vtable index,
- the pred_or_func, sym_name and user arity of the predicate or function
that the method procedure is a part of, to make it simple to test
whether two method_infos represent different modes of the same predicate
or function, or not,
- the original pred_proc_id of the method procedure, which never changes,
and
- the current pred_proc_id, which program transformations *can* change.
compiler/hlds_class.m:
Make the change above in the representations of class and instance
definitions.
Put the fields of both types into a better order, by putting
related fields next to each other.
Put a notag wrapper around method procedure numbers to prevent
accidentally mixing them up with plain integers.
Add some utility functions.
compiler/prog_data.m:
Replace three fields containing pred_or_func, sym_name and arity
in the parse tree representation of instance methods with just one,
which contains all three pieces of info. This makes it easier to operate
on them as a unit.
Change the representation of methods defined by clauses from a list
of clauses to a cord of clauses, since this supports constant-time
append.
compiler/hlds_goal.m:
Switch from plain ints to the new notag representation of method
procedure numbers in method call goals.
compiler/add_class.m:
Simplify the code for adding new classes to the HLDS.
Give some predicates better names.
compiler/check_typeclass.m:
Significantly simplify the code for that generates the pred_infos and
proc_infos implementing all the methods of an instances definition,
and construct lists of method_infos instead of lists of pred_proc_ids.
Give some predicates better names.
Some error messages about problems in instance definitions started with
In instance declaration for class/arity:
while others started with
In instance declaration for class(module_a.foo, module_b.bar):
Replace both with
In instance declaration for class(foo, bar):
because it contains more useful information than the first, and less
non-useful information than the second. Improve the wording of some
error messages.
Factor out some common code.
compiler/prog_mode.m:
compiler/prog_type.m:
compiler/prog_util.m:
Generalize the existing predicates for stripping "builtin.m" module
qualifiers from sym_names, cons_ids, insts, types and modes
to allow also the stripping of *all* module qualifiers. This capability
is now used when we print an instance's type vector as a context
for diagnostics about problems inside instance definitions.
compiler/add_pred.m:
Add a mechanism for returning the pred_id of a newly created pred_info,
whether or not it was declared using a predmode declaration. This
capability is now needed by add_class.m.
Move the code creating an error message into its own function, and export
that function for add_class.m.
compiler/polymorphism_type_info.m:
Fix some comment rot.
compiler/base_typeclass_info.m:
compiler/call_gen.m:
compiler/dead_proc_elim.m:
compiler/deep_profiling.m:
compiler/direct_arg_in_out.m:
compiler/error_msg_inst.m:
compiler/float_regs.m:
compiler/get_dependencies.m:
compiler/higher_order.m:
compiler/hlds_error_util.m:
compiler/hlds_out_goal.m:
compiler/hlds_out_typeclass_table.m:
compiler/instance_method_clauses.m:
compiler/intermod.m:
compiler/make_hlds_error.m:
compiler/ml_call_gen.m:
compiler/mode_errors.m:
compiler/modes.m:
compiler/module_qual.qualify_items.m:
compiler/old_type_constraints.m:
compiler/parse_class.m:
compiler/parse_tree_out.m:
compiler/parse_tree_out_inst.m:
compiler/polymorphism_post_copy.m:
compiler/polymorphism_type_class_info.m:
compiler/prog_item.m:
compiler/prog_rep.m:
compiler/recompilation.usage.m:
compiler/state_var.m:
compiler/type_class_info.m:
compiler/typecheck_debug.m:
compiler/typecheck_error_type_assign.m:
compiler/typecheck_errors.m:
compiler/typecheck_msgs.m:
compiler/unused_imports.m:
compiler/xml_documentation.m:
Conform to the changes above.
tests/invalid/bug476.err_exp:
tests/invalid/tc_err1.err_exp:
tests/invalid/tc_err2.err_exp:
tests/invalid/typeclass_bogus_method.err_exp:
tests/invalid/typeclass_missing_mode.err_exp:
tests/invalid/typeclass_missing_mode_2.err_exp:
tests/invalid/typeclass_mode.err_exp:
tests/invalid/typeclass_mode_2.err_exp:
tests/invalid/typeclass_mode_3.err_exp:
tests/invalid/typeclass_mode_4.err_exp:
tests/invalid/typeclass_test_10.err_exp:
tests/invalid/typeclass_test_3.err_exp:
tests/invalid/typeclass_test_4.err_exp:
tests/invalid/typeclass_test_5.err_exp:
tests/invalid/typeclass_test_9.err_exp:
Expect the updated wording of some error messages.
1933 lines
76 KiB
Mathematica
1933 lines
76 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 2001-2012 The University of Melbourne.
|
|
% Copyright (C) 2015, 2017 The Mercury team.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% File: deep_profiling.m.
|
|
% Main author: conway.
|
|
%
|
|
% This module applies the deep profiling transformation described in the paper
|
|
% ``Engineering a profiler for a logic programming language'' by Thomas Conway
|
|
% and Zoltan Somogyi.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module ll_backend.deep_profiling.
|
|
:- interface.
|
|
|
|
:- import_module hlds.
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.var_table.
|
|
|
|
:- import_module list.
|
|
:- import_module maybe.
|
|
|
|
:- pred apply_deep_profiling_transform(module_info::in, module_info::out)
|
|
is det.
|
|
|
|
:- pred generate_deep_call(module_info::in, string::in, int::in,
|
|
list(prog_var)::in, maybe(list(prog_var))::in, determinism::in,
|
|
hlds_goal::out) is det.
|
|
|
|
:- pred generate_deep_const_unify(cons_id::in, prog_var::in, hlds_goal::out)
|
|
is det.
|
|
|
|
:- pred get_deep_profile_builtin_ppid(module_info::in, string::in, int::in,
|
|
pred_id::out, proc_id::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Utility functions exported to coverage_profiling.m.
|
|
%
|
|
|
|
:- pred generate_var_int(string::in, prog_var::out,
|
|
var_table::in, var_table::out) is det.
|
|
|
|
:- pred generate_var_c_ptr(string::in, prog_var::out,
|
|
var_table::in, var_table::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module check_hlds.
|
|
:- import_module check_hlds.mode_top_functor.
|
|
:- import_module hlds.code_model.
|
|
:- import_module hlds.goal_path.
|
|
:- import_module hlds.goal_util.
|
|
:- import_module hlds.hlds_class.
|
|
:- import_module hlds.hlds_dependency_graph.
|
|
:- import_module hlds.hlds_out.
|
|
:- import_module hlds.hlds_out.hlds_out_util.
|
|
:- import_module hlds.hlds_rtti.
|
|
:- import_module hlds.instmap.
|
|
:- import_module hlds.make_goal.
|
|
:- import_module hlds.passes_aux.
|
|
:- import_module hlds.pred_name.
|
|
:- import_module hlds.pred_table.
|
|
:- import_module libs.
|
|
:- import_module libs.dependency_graph.
|
|
:- import_module libs.file_util.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.options.
|
|
:- import_module ll_backend.coverage_profiling.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.builtin_modules.
|
|
:- import_module mdbcomp.goal_path.
|
|
:- import_module mdbcomp.prim_data.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.builtin_lib_types.
|
|
:- import_module parse_tree.prog_data_foreign.
|
|
:- import_module parse_tree.prog_type.
|
|
:- import_module parse_tree.set_of_var.
|
|
:- import_module transform_hlds.
|
|
:- import_module transform_hlds.dead_proc_elim.
|
|
|
|
:- import_module assoc_list.
|
|
:- import_module bool.
|
|
:- import_module cord.
|
|
:- import_module counter.
|
|
:- import_module int.
|
|
:- import_module map.
|
|
:- import_module pair.
|
|
:- import_module require.
|
|
:- import_module set.
|
|
:- import_module string.
|
|
:- import_module term_context.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
apply_deep_profiling_transform(!ModuleInfo) :-
|
|
% XXX The dead proc elimination pass changes the status of opt_imported
|
|
% predicates, which changes what labels they get generated. The
|
|
% call_site_static structures we generate must match the labels created
|
|
% during code generation.
|
|
dead_proc_elim(elim_opt_imported, _, _, !ModuleInfo),
|
|
module_info_get_globals(!.ModuleInfo, Globals),
|
|
globals.lookup_bool_option(Globals, deep_profile_tail_recursion,
|
|
TailRecursion),
|
|
(
|
|
TailRecursion = yes,
|
|
apply_deep_prof_tail_rec_transform(!ModuleInfo)
|
|
;
|
|
TailRecursion = no
|
|
),
|
|
module_info_get_valid_pred_ids(!.ModuleInfo, PredIds),
|
|
module_info_get_pred_id_table(!.ModuleInfo, PredIdTable0),
|
|
list.foldl(deep_prof_transform_pred(!.ModuleInfo), PredIds,
|
|
PredIdTable0, PredIdTable),
|
|
module_info_set_pred_id_table(PredIdTable, !ModuleInfo).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred apply_deep_prof_tail_rec_transform(module_info::in, module_info::out)
|
|
is det.
|
|
|
|
apply_deep_prof_tail_rec_transform(!ModuleInfo) :-
|
|
module_info_ensure_dependency_info(!ModuleInfo, DepInfo),
|
|
SCCs = dependency_info_get_bottom_up_sccs(DepInfo),
|
|
list.foldl(apply_deep_prof_tail_rec_transform_to_scc, SCCs, !ModuleInfo).
|
|
|
|
:- pred apply_deep_prof_tail_rec_transform_to_scc(scc::in,
|
|
module_info::in, module_info::out) is det.
|
|
|
|
apply_deep_prof_tail_rec_transform_to_scc(SCC, !ModuleInfo) :-
|
|
% For the time being, we only look for self-tail-recursive calls.
|
|
% If the SCC contains more than one procedure, a self-tail-recursive
|
|
% call in Proc A could end up calling the other procedure Proc B
|
|
% in the SCC, which could then call back to Proc A. This would screw up
|
|
% our bookkeeping.
|
|
( if set.is_singleton(SCC, PredProcId) then
|
|
apply_deep_prof_tail_rec_transform_to_proc(PredProcId, !ModuleInfo)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred apply_deep_prof_tail_rec_transform_to_proc(pred_proc_id::in,
|
|
module_info::in, module_info::out) is det.
|
|
|
|
apply_deep_prof_tail_rec_transform_to_proc(PredProcId, !ModuleInfo) :-
|
|
PredProcId = proc(PredId, ProcId),
|
|
module_info_pred_info(!.ModuleInfo, PredId, PredInfo0),
|
|
pred_info_get_arg_types(PredInfo0, Types),
|
|
pred_info_get_origin(PredInfo0, Origin),
|
|
pred_info_get_proc_table(PredInfo0, ProcTable0),
|
|
map.lookup(ProcTable0, ProcId, ProcInfo0),
|
|
proc_info_get_goal(ProcInfo0, Goal0),
|
|
proc_info_interface_determinism(ProcInfo0, Detism),
|
|
( if
|
|
determinism_components(Detism, _CanFail, SolnCount),
|
|
SolnCount \= at_most_many,
|
|
proc_info_get_headvars(ProcInfo0, HeadVars),
|
|
proc_info_get_argmodes(ProcInfo0, Modes),
|
|
find_list_of_output_args(!.ModuleInfo, HeadVars, Types, Modes,
|
|
Outputs),
|
|
clone_proc_id(ProcTable0, ProcId, CloneProcId),
|
|
ClonePredProcId = proc(PredId, CloneProcId),
|
|
TailRecInfo = deep_prof_tail_rec_info(!.ModuleInfo,
|
|
[PredProcId - ClonePredProcId], Detism, Outputs),
|
|
apply_deep_prof_tail_rec_to_goal(Goal0, Goal, TailRecInfo,
|
|
no, FoundTailCall, _Continue),
|
|
FoundTailCall = yes,
|
|
% The unification or comparison procedure for a type can be called
|
|
% from builtin.unify or builtin.compare respectively, through the
|
|
% type_ctor_info of an argument type. This means that we cannot
|
|
% guarantee that a unification or comparison procedure is alone
|
|
% in its SCC unless it cannot call builtin.unify and builtin.compare.
|
|
(
|
|
Origin = origin_compiler(made_for_uci(_, _))
|
|
=>
|
|
goal_contains_builtin_unify_or_compare(Goal) = no
|
|
)
|
|
then
|
|
proc_info_set_goal(Goal, ProcInfo0, ProcInfo1),
|
|
figure_out_rec_call_numbers(Goal, 0, _Num, [], TailCallSites),
|
|
OrigDeepRecInfo = yes(deep_recursion_info(
|
|
deep_prof_outer_proc(ClonePredProcId),
|
|
[visible_scc_data(PredProcId, ClonePredProcId, TailCallSites)])),
|
|
make_deep_original_body(!.ModuleInfo, ProcInfo0, DeepOriginalBody),
|
|
OrigDeepProfileInfo = deep_profile_proc_info(OrigDeepRecInfo, no,
|
|
DeepOriginalBody),
|
|
CloneDeepRecInfo = yes(deep_recursion_info(
|
|
deep_prof_inner_proc(PredProcId),
|
|
[visible_scc_data(PredProcId, ClonePredProcId, TailCallSites)])),
|
|
CloneDeepProfileInfo = deep_profile_proc_info(CloneDeepRecInfo, no,
|
|
DeepOriginalBody),
|
|
proc_info_set_maybe_deep_profile_info(yes(OrigDeepProfileInfo),
|
|
ProcInfo1, ProcInfo),
|
|
proc_info_set_maybe_deep_profile_info(yes(CloneDeepProfileInfo),
|
|
ProcInfo1, CloneProcInfo),
|
|
map.det_update(ProcId, ProcInfo, ProcTable0, ProcTable1),
|
|
map.det_insert(CloneProcId, CloneProcInfo, ProcTable1, ProcTable),
|
|
pred_info_set_proc_table(ProcTable, PredInfo0, PredInfo),
|
|
module_info_set_pred_info(PredId, PredInfo, !ModuleInfo)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred find_list_of_output_args(module_info::in, list(prog_var)::in,
|
|
list(mer_type)::in, list(mer_mode)::in, list(prog_var)::out) is det.
|
|
|
|
find_list_of_output_args(ModuleInfo, Vars, Types, Modes, !:Outputs) :-
|
|
( if
|
|
find_list_of_output_args_2(ModuleInfo, Vars, Types, Modes, !:Outputs)
|
|
then
|
|
true
|
|
else
|
|
unexpected($pred, "list length mismatch")
|
|
).
|
|
|
|
:- pred find_list_of_output_args_2(module_info::in, list(prog_var)::in,
|
|
list(mer_type)::in, list(mer_mode)::in, list(prog_var)::out) is semidet.
|
|
|
|
find_list_of_output_args_2(_, [], [], [], []).
|
|
find_list_of_output_args_2(ModuleInfo, [Var | Vars], [Type | Types],
|
|
[Mode | Modes], Outputs) :-
|
|
find_list_of_output_args_2(ModuleInfo, Vars, Types, Modes, LaterOutputs),
|
|
mode_to_top_functor_mode(ModuleInfo, Mode, Type, TopFunctorMode),
|
|
(
|
|
TopFunctorMode = top_in,
|
|
Outputs = LaterOutputs
|
|
;
|
|
( TopFunctorMode = top_out
|
|
; TopFunctorMode = top_unused
|
|
),
|
|
Outputs = [Var | LaterOutputs]
|
|
).
|
|
|
|
:- func goal_contains_builtin_unify_or_compare(hlds_goal) = bool.
|
|
|
|
goal_contains_builtin_unify_or_compare(Goal) = Contains :-
|
|
Goal = hlds_goal(GoalExpr, _GoalInfo),
|
|
(
|
|
GoalExpr = unify(_, _, _, _, _),
|
|
Contains = no
|
|
;
|
|
( GoalExpr = generic_call(_, _, _, _, _)
|
|
; GoalExpr = plain_call(_, _, _, _, _, _)
|
|
),
|
|
% Unfortunately, even if the procedure we are calling is neither
|
|
% builtin.unify nor builtin.compare, we cannot know whether it
|
|
% can call those predicates directly or indirectly.
|
|
Contains = yes
|
|
;
|
|
GoalExpr = call_foreign_proc(Attributes, _, _, _, _, _, _),
|
|
MayCallMercury = get_may_call_mercury(Attributes),
|
|
(
|
|
MayCallMercury = proc_will_not_call_mercury,
|
|
Contains = no
|
|
;
|
|
MayCallMercury = proc_may_call_mercury,
|
|
% The Mercury code may call builtin.unify or builtin.compare.
|
|
Contains = yes
|
|
)
|
|
;
|
|
( GoalExpr = conj(_, Goals)
|
|
; GoalExpr = disj(Goals)
|
|
),
|
|
Contains = goals_contain_builtin_unify_or_compare(Goals)
|
|
;
|
|
GoalExpr = switch(_, _, Cases),
|
|
Contains = cases_contain_builtin_unify_or_compare(Cases)
|
|
;
|
|
GoalExpr = if_then_else(_, Cond, Then, Else),
|
|
( if
|
|
goal_contains_builtin_unify_or_compare(Cond) = no,
|
|
goal_contains_builtin_unify_or_compare(Then) = no,
|
|
goal_contains_builtin_unify_or_compare(Else) = no
|
|
then
|
|
Contains = no
|
|
else
|
|
Contains = yes
|
|
)
|
|
;
|
|
( GoalExpr = negation(SubGoal)
|
|
; GoalExpr = scope(_, SubGoal)
|
|
),
|
|
Contains = goal_contains_builtin_unify_or_compare(SubGoal)
|
|
;
|
|
GoalExpr = shorthand(_),
|
|
unexpected($pred, "shorthand")
|
|
).
|
|
|
|
:- func goals_contain_builtin_unify_or_compare(list(hlds_goal)) = bool.
|
|
|
|
goals_contain_builtin_unify_or_compare([]) = no.
|
|
goals_contain_builtin_unify_or_compare([Goal | Goals]) = Contains :-
|
|
( if goal_contains_builtin_unify_or_compare(Goal) = yes then
|
|
Contains = yes
|
|
else
|
|
Contains = goals_contain_builtin_unify_or_compare(Goals)
|
|
).
|
|
|
|
:- func cases_contain_builtin_unify_or_compare(list(case)) = bool.
|
|
|
|
cases_contain_builtin_unify_or_compare([]) = no.
|
|
cases_contain_builtin_unify_or_compare([Case | Cases]) = Contains :-
|
|
Case = case(_, _, Goal),
|
|
( if goal_contains_builtin_unify_or_compare(Goal) = yes then
|
|
Contains = yes
|
|
else
|
|
Contains = cases_contain_builtin_unify_or_compare(Cases)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type deep_prof_tail_rec_info
|
|
---> deep_prof_tail_rec_info(
|
|
dptri_moduleinfo :: module_info,
|
|
dptri_scc_ppids :: assoc_list(pred_proc_id),
|
|
dptri_detism :: determinism,
|
|
dptri_outputs :: list(prog_var)
|
|
).
|
|
|
|
:- pred apply_deep_prof_tail_rec_to_goal(hlds_goal::in, hlds_goal::out,
|
|
deep_prof_tail_rec_info::in, bool::in, bool::out,
|
|
maybe(list(prog_var))::out) is det.
|
|
|
|
apply_deep_prof_tail_rec_to_goal(Goal0, Goal, TailRecInfo, !FoundTailCall,
|
|
Continue) :-
|
|
Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
|
|
(
|
|
GoalExpr0 = call_foreign_proc(_, _, _, _, _, _, _),
|
|
Goal = Goal0,
|
|
Continue = no
|
|
;
|
|
GoalExpr0 = plain_call(PredId, ProcId, ArgVars, Builtin, UnifyContext,
|
|
SymName),
|
|
( if
|
|
PredProcId = proc(PredId, ProcId),
|
|
assoc_list.search(TailRecInfo ^ dptri_scc_ppids, PredProcId,
|
|
ClonePredProcId),
|
|
module_info_pred_proc_info(TailRecInfo ^ dptri_moduleinfo,
|
|
PredId, ProcId, PredInfo, ProcInfo),
|
|
proc_info_interface_determinism(ProcInfo, CallDetism),
|
|
CallDetism = TailRecInfo ^ dptri_detism,
|
|
pred_info_get_arg_types(PredInfo, Types),
|
|
proc_info_get_argmodes(ProcInfo, Modes),
|
|
find_list_of_output_args(TailRecInfo ^ dptri_moduleinfo,
|
|
ArgVars, Types, Modes, CallOutputs),
|
|
CallOutputs = TailRecInfo ^ dptri_outputs,
|
|
Builtin = not_builtin
|
|
then
|
|
ClonePredProcId = proc(ClonePredId, CloneProcId),
|
|
GoalExpr = plain_call(ClonePredId, CloneProcId, ArgVars,
|
|
Builtin, UnifyContext, SymName),
|
|
goal_info_add_feature(feature_deep_self_tail_rec_call,
|
|
GoalInfo0, GoalInfo),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo),
|
|
!:FoundTailCall = yes
|
|
else
|
|
Goal = Goal0
|
|
),
|
|
Continue = no
|
|
;
|
|
GoalExpr0 = generic_call(_, _, _, _, _),
|
|
Goal = Goal0,
|
|
Continue = no
|
|
;
|
|
GoalExpr0 = unify(_, _, _, Unify0, _),
|
|
Goal = Goal0,
|
|
(
|
|
Unify0 = assign(ToVar, FromVar),
|
|
apply_deep_prof_tail_rec_to_assign(TailRecInfo ^ dptri_outputs,
|
|
ToVar, FromVar, Outputs),
|
|
Continue = yes(Outputs)
|
|
;
|
|
( Unify0 = construct(_, _, _, _, _, __, _)
|
|
; Unify0 = deconstruct(_, _, _, _, __, _)
|
|
; Unify0 = simple_test(_, _)
|
|
; Unify0 = complicated_unify(_, _, _)
|
|
),
|
|
Continue = no
|
|
)
|
|
;
|
|
GoalExpr0 = conj(ConjType, Goals0),
|
|
(
|
|
ConjType = plain_conj,
|
|
apply_deep_prof_tail_rec_to_conj(Goals0, Goals, TailRecInfo,
|
|
!FoundTailCall, Continue),
|
|
GoalExpr = conj(ConjType, Goals),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo0)
|
|
;
|
|
ConjType = parallel_conj,
|
|
Goal = Goal0,
|
|
Continue = no
|
|
)
|
|
;
|
|
GoalExpr0 = disj(Goals0),
|
|
apply_deep_prof_tail_rec_to_disj(Goals0, Goals, TailRecInfo,
|
|
!FoundTailCall),
|
|
GoalExpr = disj(Goals),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo0),
|
|
Continue = no
|
|
;
|
|
GoalExpr0 = switch(Var, CanFail, Cases0),
|
|
apply_deep_prof_tail_rec_to_cases(Cases0, Cases, TailRecInfo,
|
|
!FoundTailCall),
|
|
GoalExpr = switch(Var, CanFail, Cases),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo0),
|
|
Continue = no
|
|
;
|
|
GoalExpr0 = if_then_else(Vars, Cond, Then0, Else0),
|
|
apply_deep_prof_tail_rec_to_goal(Then0, Then, TailRecInfo,
|
|
!FoundTailCall, _),
|
|
apply_deep_prof_tail_rec_to_goal(Else0, Else, TailRecInfo,
|
|
!FoundTailCall, _),
|
|
GoalExpr = if_then_else(Vars, Cond, Then, Else),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo0),
|
|
Continue = no
|
|
;
|
|
GoalExpr0 = scope(_, _),
|
|
Goal = Goal0,
|
|
Continue = no
|
|
;
|
|
GoalExpr0 = negation(_),
|
|
Goal = Goal0,
|
|
Continue = no
|
|
;
|
|
GoalExpr0 = shorthand(_),
|
|
unexpected($pred, "shorthand")
|
|
).
|
|
|
|
:- pred apply_deep_prof_tail_rec_to_assign(list(prog_var)::in,
|
|
prog_var::in, prog_var::in, list(prog_var)::out) is det.
|
|
|
|
apply_deep_prof_tail_rec_to_assign([], _, _, []).
|
|
apply_deep_prof_tail_rec_to_assign([Output0 | Outputs0], ToVar, FromVar,
|
|
[Output | Outputs]) :-
|
|
( if ToVar = Output0 then
|
|
Output = FromVar
|
|
else
|
|
Output = Output0
|
|
),
|
|
apply_deep_prof_tail_rec_to_assign(Outputs0, ToVar, FromVar, Outputs).
|
|
|
|
:- pred apply_deep_prof_tail_rec_to_conj(list(hlds_goal)::in,
|
|
list(hlds_goal)::out, deep_prof_tail_rec_info::in,
|
|
bool::in, bool::out, maybe(list(prog_var))::out) is det.
|
|
|
|
apply_deep_prof_tail_rec_to_conj([], [], TailRecInfo,
|
|
!FoundTailCall, yes(TailRecInfo ^ dptri_outputs)).
|
|
apply_deep_prof_tail_rec_to_conj([Goal0 | Goals0], [Goal | Goals], TailRecInfo,
|
|
!FoundTailCall, Continue) :-
|
|
apply_deep_prof_tail_rec_to_conj(Goals0, Goals, TailRecInfo,
|
|
!FoundTailCall, TailContinue),
|
|
(
|
|
TailContinue = yes(Outputs),
|
|
HeadTailRecInfo = TailRecInfo ^ dptri_outputs := Outputs,
|
|
apply_deep_prof_tail_rec_to_goal(Goal0, Goal, HeadTailRecInfo,
|
|
!FoundTailCall, Continue)
|
|
;
|
|
TailContinue = no,
|
|
Goal = Goal0,
|
|
Continue = no
|
|
).
|
|
|
|
:- pred apply_deep_prof_tail_rec_to_disj(list(hlds_goal)::in,
|
|
list(hlds_goal)::out, deep_prof_tail_rec_info::in, bool::in, bool::out)
|
|
is det.
|
|
|
|
apply_deep_prof_tail_rec_to_disj([], [], _, !FoundTailCall).
|
|
apply_deep_prof_tail_rec_to_disj([Goal0], [Goal], TailRecInfo,
|
|
!FoundTailCall) :-
|
|
apply_deep_prof_tail_rec_to_goal(Goal0, Goal, TailRecInfo, !FoundTailCall,
|
|
_).
|
|
apply_deep_prof_tail_rec_to_disj([Goal0 | Goals0], [Goal0 | Goals],
|
|
TailRecInfo, !FoundTailCall) :-
|
|
Goals0 = [_ | _],
|
|
apply_deep_prof_tail_rec_to_disj(Goals0, Goals, TailRecInfo,
|
|
!FoundTailCall).
|
|
|
|
:- pred apply_deep_prof_tail_rec_to_cases(list(case)::in, list(case)::out,
|
|
deep_prof_tail_rec_info::in, bool::in, bool::out) is det.
|
|
|
|
apply_deep_prof_tail_rec_to_cases([], [], _, !FoundTailCall).
|
|
apply_deep_prof_tail_rec_to_cases([Case0 | Cases0], [Case | Cases],
|
|
TailRecInfo, !FoundTailCall) :-
|
|
Case0 = case(MainConsId, OtherConsIds, Goal0),
|
|
apply_deep_prof_tail_rec_to_goal(Goal0, Goal, TailRecInfo,
|
|
!FoundTailCall, _),
|
|
Case = case(MainConsId, OtherConsIds, Goal),
|
|
apply_deep_prof_tail_rec_to_cases(Cases0, Cases, TailRecInfo,
|
|
!FoundTailCall).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred figure_out_rec_call_numbers(hlds_goal::in, int::in, int::out,
|
|
list(int)::in, list(int)::out) is det.
|
|
|
|
figure_out_rec_call_numbers(Goal, !N, !TailCallSites) :-
|
|
Goal = hlds_goal(GoalExpr, GoalInfo),
|
|
(
|
|
GoalExpr = call_foreign_proc(Attrs, _, _, _, _, _, _),
|
|
MayCallMercury = get_may_call_mercury(Attrs),
|
|
(
|
|
MayCallMercury = proc_may_call_mercury,
|
|
!:N = !.N + 1
|
|
;
|
|
MayCallMercury = proc_will_not_call_mercury
|
|
)
|
|
;
|
|
GoalExpr = plain_call(_, _, _, BuiltinState, _, _),
|
|
Features = goal_info_get_features(GoalInfo),
|
|
( if set.member(feature_deep_self_tail_rec_call, Features) then
|
|
!:TailCallSites = [!.N | !.TailCallSites]
|
|
else
|
|
true
|
|
),
|
|
(
|
|
BuiltinState = not_builtin,
|
|
!:N = !.N + 1
|
|
;
|
|
BuiltinState = inline_builtin
|
|
)
|
|
;
|
|
GoalExpr = generic_call(_, _, _, _, _),
|
|
!:N = !.N + 1
|
|
;
|
|
GoalExpr = unify(_, _, _, _, _)
|
|
;
|
|
GoalExpr = conj(_ConjType, Goals),
|
|
figure_out_rec_call_numbers_in_goal_list(Goals, !N, !TailCallSites)
|
|
;
|
|
GoalExpr = disj(Goals),
|
|
figure_out_rec_call_numbers_in_goal_list(Goals, !N, !TailCallSites)
|
|
;
|
|
GoalExpr = switch(_, _, Cases),
|
|
figure_out_rec_call_numbers_in_case_list(Cases, !N, !TailCallSites)
|
|
;
|
|
GoalExpr = if_then_else(_, Cond, Then, Else),
|
|
figure_out_rec_call_numbers(Cond, !N, !TailCallSites),
|
|
figure_out_rec_call_numbers(Then, !N, !TailCallSites),
|
|
figure_out_rec_call_numbers(Else, !N, !TailCallSites)
|
|
;
|
|
GoalExpr = negation(SubGoal),
|
|
figure_out_rec_call_numbers(SubGoal, !N, !TailCallSites)
|
|
;
|
|
GoalExpr = scope(Reason, SubGoal),
|
|
( if
|
|
Reason = from_ground_term(_, FGT),
|
|
( FGT = from_ground_term_construct
|
|
; FGT = from_ground_term_deconstruct
|
|
)
|
|
then
|
|
true
|
|
else
|
|
figure_out_rec_call_numbers(SubGoal, !N, !TailCallSites)
|
|
)
|
|
;
|
|
GoalExpr = shorthand(_),
|
|
unexpected($pred, "shorthand")
|
|
).
|
|
|
|
:- pred figure_out_rec_call_numbers_in_goal_list(list(hlds_goal)::in,
|
|
int::in, int::out, list(int)::in, list(int)::out) is det.
|
|
|
|
figure_out_rec_call_numbers_in_goal_list([], !N, !TailCallSites).
|
|
figure_out_rec_call_numbers_in_goal_list([Goal|Goals], !N, !TailCallSites) :-
|
|
figure_out_rec_call_numbers(Goal, !N, !TailCallSites),
|
|
figure_out_rec_call_numbers_in_goal_list(Goals, !N, !TailCallSites).
|
|
|
|
:- pred figure_out_rec_call_numbers_in_case_list(list(case)::in,
|
|
int::in, int::out, list(int)::in, list(int)::out) is det.
|
|
|
|
figure_out_rec_call_numbers_in_case_list([], !N, !TailCallSites).
|
|
figure_out_rec_call_numbers_in_case_list([Case|Cases], !N, !TailCallSites) :-
|
|
Case = case(_, _, Goal),
|
|
figure_out_rec_call_numbers(Goal, !N, !TailCallSites),
|
|
figure_out_rec_call_numbers_in_case_list(Cases, !N, !TailCallSites).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred deep_prof_transform_pred(module_info::in, pred_id::in,
|
|
pred_id_table::in, pred_id_table::out) is det.
|
|
|
|
deep_prof_transform_pred(ModuleInfo, PredId, !PredMap) :-
|
|
map.lookup(!.PredMap, PredId, PredInfo0),
|
|
ProcIds = pred_info_valid_non_imported_procids(PredInfo0),
|
|
pred_info_get_proc_table(PredInfo0, ProcTable0),
|
|
list.foldl(deep_prof_maybe_transform_proc(ModuleInfo, PredId),
|
|
ProcIds, ProcTable0, ProcTable),
|
|
pred_info_set_proc_table(ProcTable, PredInfo0, PredInfo),
|
|
map.det_update(PredId, PredInfo, !PredMap).
|
|
|
|
:- pred deep_prof_maybe_transform_proc(module_info::in,
|
|
pred_id::in, proc_id::in, proc_table::in, proc_table::out) is det.
|
|
|
|
deep_prof_maybe_transform_proc(ModuleInfo, PredId, ProcId, !ProcTable) :-
|
|
map.lookup(!.ProcTable, ProcId, ProcInfo0),
|
|
PredModuleName = predicate_module(ModuleInfo, PredId),
|
|
( if
|
|
% We don't want to transform the procedures for managing the deep
|
|
% profiling call graph, or we'd get infinite recursion.
|
|
PredModuleName = mercury_profiling_builtin_module
|
|
then
|
|
true
|
|
else
|
|
trace [io(!IO)] (
|
|
module_info_get_globals(ModuleInfo, Globals),
|
|
globals.lookup_bool_option(Globals, very_verbose, VeryVerbose),
|
|
ProcName = pred_proc_id_pair_to_user_string(ModuleInfo,
|
|
PredId, ProcId),
|
|
get_progress_output_stream(ModuleInfo, ProgressStream, !IO),
|
|
maybe_write_string(ProgressStream, VeryVerbose,
|
|
string.format("%% Deep profiling: %s\n", [s(ProcName)]), !IO)
|
|
),
|
|
deep_prof_transform_proc(ModuleInfo, proc(PredId, ProcId),
|
|
ProcInfo0, ProcInfo),
|
|
map.det_update(ProcId, ProcInfo, !ProcTable)
|
|
).
|
|
|
|
:- pred deep_prof_transform_proc(module_info::in, pred_proc_id::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
|
|
deep_prof_transform_proc(ModuleInfo, PredProcId, !ProcInfo) :-
|
|
proc_info_get_maybe_deep_profile_info(!.ProcInfo, MaybeDeepInfo),
|
|
(
|
|
MaybeDeepInfo = yes(DeepInfo0),
|
|
DeepInfo0 = deep_profile_proc_info(MaybeDeepRecInfo, _, OrigBody),
|
|
( if
|
|
MaybeDeepRecInfo = yes(RecInfo),
|
|
RecInfo ^ dri_role = deep_prof_inner_proc(_)
|
|
then
|
|
deep_prof_transform_inner_proc(ModuleInfo, PredProcId, !ProcInfo),
|
|
MaybeDeepLayoutInfo = no
|
|
else
|
|
deep_prof_transform_normal_proc(ModuleInfo, PredProcId, !ProcInfo,
|
|
DeepLayoutInfo),
|
|
MaybeDeepLayoutInfo = yes(DeepLayoutInfo)
|
|
)
|
|
;
|
|
MaybeDeepInfo = no,
|
|
make_deep_original_body(ModuleInfo, !.ProcInfo, OrigBody),
|
|
deep_prof_transform_normal_proc(ModuleInfo, PredProcId, !ProcInfo,
|
|
DeepLayoutInfo),
|
|
MaybeDeepLayoutInfo = yes(DeepLayoutInfo),
|
|
MaybeDeepRecInfo = no
|
|
),
|
|
DeepInfo = deep_profile_proc_info(MaybeDeepRecInfo, MaybeDeepLayoutInfo,
|
|
OrigBody),
|
|
proc_info_set_maybe_deep_profile_info(yes(DeepInfo), !ProcInfo).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred make_deep_original_body(module_info::in, proc_info::in,
|
|
deep_original_body::out) is det.
|
|
|
|
make_deep_original_body(ModuleInfo, ProcInfo, DeepOriginalBody) :-
|
|
proc_info_get_goal(ProcInfo, Body),
|
|
proc_info_get_headvars(ProcInfo, HeadVars),
|
|
proc_info_get_initial_instmap(ModuleInfo, ProcInfo, Instmap),
|
|
proc_info_get_var_table(ProcInfo, VarTable),
|
|
proc_info_get_declared_determinism(ProcInfo, MaybeDetism),
|
|
(
|
|
MaybeDetism = yes(Detism)
|
|
;
|
|
MaybeDetism = no,
|
|
proc_info_get_inferred_determinism(ProcInfo, Detism)
|
|
),
|
|
DeepOriginalBody = deep_original_body(Body, HeadVars, Instmap,
|
|
VarTable, Detism).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% This structure contains stateful information used throughout the deep
|
|
% profiling transformation of a procedure.
|
|
%
|
|
:- type deep_info
|
|
---> deep_info(
|
|
deep_module_info :: module_info,
|
|
deep_pred_proc_id :: pred_proc_id,
|
|
deep_containing_goal_map:: containing_goal_map,
|
|
deep_current_csd :: prog_var,
|
|
deep_site_num_counter :: counter,
|
|
deep_call_sites :: cord(call_site_static_data),
|
|
deep_var_table :: var_table,
|
|
deep_proc_filename :: string,
|
|
deep_maybe_rec_info :: maybe(deep_recursion_info)
|
|
).
|
|
|
|
% Transfrom a procedure.
|
|
%
|
|
:- pred deep_prof_transform_normal_proc(module_info::in, pred_proc_id::in,
|
|
proc_info::in, proc_info::out, hlds_deep_layout::out) is det.
|
|
|
|
deep_prof_transform_normal_proc(ModuleInfo, PredProcId, !ProcInfo,
|
|
DeepLayoutInfo) :-
|
|
fill_goal_id_slots_in_proc(ModuleInfo, ContainingGoalMap, !ProcInfo),
|
|
|
|
module_info_get_globals(ModuleInfo, Globals),
|
|
some [!VarTable, !DeepInfo, !Goal] (
|
|
proc_info_get_var_table(!.ProcInfo, !:VarTable),
|
|
proc_info_get_goal(!.ProcInfo, !:Goal),
|
|
!.Goal = hlds_goal(_, GoalInfo0),
|
|
|
|
generate_var_c_ptr("TopCSD", TopCSD, !VarTable),
|
|
generate_var_c_ptr("MiddleCSD", MiddleCSD, !VarTable),
|
|
generate_var_c_ptr("ProcStaticLayout", ProcStaticVar, !VarTable),
|
|
|
|
proc_info_get_context(!.ProcInfo, Context),
|
|
FileName = term_context.context_file(Context),
|
|
LineNumber = term_context.context_line(Context),
|
|
|
|
proc_info_get_maybe_deep_profile_info(!.ProcInfo, MaybeDeepProfInfo),
|
|
extract_deep_rec_info(MaybeDeepProfInfo, MaybeRecInfo),
|
|
!:DeepInfo = deep_info(ModuleInfo, PredProcId, ContainingGoalMap,
|
|
MiddleCSD, counter.init(0), cord.empty, !.VarTable, FileName,
|
|
MaybeRecInfo),
|
|
|
|
% This call transforms the goals of the procedure.
|
|
deep_prof_transform_goal(!Goal, _, !DeepInfo),
|
|
!:VarTable = !.DeepInfo ^ deep_var_table,
|
|
CallSites = cord.list(!.DeepInfo ^ deep_call_sites),
|
|
|
|
% Do coverage profiling if requested.
|
|
globals.lookup_bool_option(Globals, coverage_profiling,
|
|
DoCoverageProfiling),
|
|
(
|
|
DoCoverageProfiling = yes,
|
|
coverage_prof_transform_proc_body(ModuleInfo, PredProcId,
|
|
ContainingGoalMap, MaybeRecInfo, CoveragePoints,
|
|
!Goal, !VarTable)
|
|
;
|
|
DoCoverageProfiling = no,
|
|
CoveragePoints = []
|
|
),
|
|
|
|
( if
|
|
MaybeRecInfo = yes(RecInfo),
|
|
RecInfo ^ dri_role = deep_prof_inner_proc(OuterPredProcId)
|
|
then
|
|
OuterPredProcId = proc(PredId, ProcId)
|
|
else
|
|
PredProcId = proc(PredId, ProcId)
|
|
),
|
|
|
|
globals.lookup_bool_option(Globals, use_activation_counts,
|
|
UseActivationCounts),
|
|
|
|
IsInInterface = is_proc_in_interface(ModuleInfo, PredId, ProcId),
|
|
ProcStatic = hlds_proc_static(FileName, LineNumber, IsInInterface,
|
|
CallSites, CoveragePoints),
|
|
ShroudedPredProcId = shroud_pred_proc_id(proc(PredId, ProcId)),
|
|
ProcStaticConsId = deep_profiling_proc_layout(ShroudedPredProcId),
|
|
generate_deep_const_unify(ProcStaticConsId, ProcStaticVar,
|
|
BindProcStaticVarGoal),
|
|
|
|
% Wrap the procedure body inside more goals that invoke the port codes
|
|
% when necessary. When they are necessary depends on the code model
|
|
% of the procedure.
|
|
CodeModel = proc_info_interface_code_model(!.ProcInfo),
|
|
(
|
|
CodeModel = model_det,
|
|
maybe_generate_activation_ptr(UseActivationCounts, TopCSD,
|
|
MiddleCSD, MaybeActivationPtr, ExcpVars, !VarTable),
|
|
build_det_proc_body(ModuleInfo, TopCSD, MiddleCSD, ProcStaticVar,
|
|
MaybeActivationPtr, GoalInfo0, BindProcStaticVarGoal, !Goal)
|
|
;
|
|
CodeModel = model_semi,
|
|
maybe_generate_activation_ptr(UseActivationCounts, TopCSD,
|
|
MiddleCSD, MaybeActivationPtr, ExcpVars, !VarTable),
|
|
build_semi_proc_body(ModuleInfo, TopCSD, MiddleCSD, ProcStaticVar,
|
|
MaybeActivationPtr, GoalInfo0, BindProcStaticVarGoal, !Goal)
|
|
;
|
|
CodeModel = model_non,
|
|
generate_outermost_proc_dyns(UseActivationCounts, TopCSD,
|
|
MiddleCSD, MaybeOldActivationPtr, NewOutermostProcDyn,
|
|
ExcpVars, !VarTable),
|
|
build_non_proc_body(ModuleInfo, TopCSD, MiddleCSD,
|
|
ProcStaticVar, MaybeOldActivationPtr, NewOutermostProcDyn,
|
|
GoalInfo0, BindProcStaticVarGoal, !Goal)
|
|
),
|
|
|
|
proc_info_set_var_table(!.VarTable, !ProcInfo),
|
|
proc_info_set_goal(!.Goal, !ProcInfo),
|
|
DeepLayoutInfo = hlds_deep_layout(ProcStatic, ExcpVars)
|
|
).
|
|
|
|
% Transform an inner procedure for deep profiling. Inner procedures are
|
|
% created by the tail recursion preservation pass above.
|
|
%
|
|
% XXX: Inner procedures have no coverage profiling transformation done to
|
|
% them yet. This is because they are currently broken, and hence disabled.
|
|
%
|
|
:- pred deep_prof_transform_inner_proc(module_info::in, pred_proc_id::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
|
|
deep_prof_transform_inner_proc(ModuleInfo, PredProcId, !ProcInfo) :-
|
|
fill_goal_id_slots_in_proc(ModuleInfo, ContainingGoalMap, !ProcInfo),
|
|
|
|
proc_info_get_goal(!.ProcInfo, Goal0),
|
|
Goal0 = hlds_goal(_, GoalInfo0),
|
|
proc_info_get_var_table(!.ProcInfo, VarTable0),
|
|
generate_var_c_ptr("MiddleCSD", MiddleCSD, VarTable0, VarTable1),
|
|
|
|
Context = goal_info_get_context(GoalInfo0),
|
|
FileName = term_context.context_file(Context),
|
|
|
|
proc_info_get_maybe_deep_profile_info(!.ProcInfo, MaybeDeepProfInfo),
|
|
extract_deep_rec_info(MaybeDeepProfInfo, MaybeRecInfo),
|
|
DeepInfo0 = deep_info(ModuleInfo, PredProcId, ContainingGoalMap, MiddleCSD,
|
|
counter.init(0), cord.empty, VarTable1, FileName, MaybeRecInfo),
|
|
|
|
deep_prof_transform_goal(Goal0, Goal, _, DeepInfo0, DeepInfo),
|
|
|
|
VarTable = DeepInfo ^ deep_var_table,
|
|
proc_info_set_var_table(VarTable, !ProcInfo),
|
|
proc_info_set_goal(Goal, !ProcInfo).
|
|
|
|
:- func is_proc_in_interface(module_info, pred_id, proc_id) = bool.
|
|
|
|
is_proc_in_interface(ModuleInfo, PredId, _ProcId) = IsInInterface :-
|
|
module_info_pred_info(ModuleInfo, PredId, PredInfo),
|
|
( if
|
|
( pred_info_is_exported(PredInfo)
|
|
; pred_info_is_pseudo_exported(PredInfo)
|
|
)
|
|
then
|
|
IsInInterface = yes
|
|
else
|
|
IsInInterface = no
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Wrap the procedure body in the deep profiling port goals.
|
|
%
|
|
% When modifing this transformation be sure to modify original_root/3 in
|
|
% deep_profiler/program_representation_utils.m which must be able to undo
|
|
% this transformation.
|
|
%
|
|
:- pred build_det_proc_body(module_info::in, prog_var::in, prog_var::in,
|
|
prog_var::in, maybe(prog_var)::in, hlds_goal_info::in, hlds_goal::in,
|
|
hlds_goal::in, hlds_goal::out) is det.
|
|
|
|
build_det_proc_body(ModuleInfo, TopCSD, MiddleCSD, ProcStaticVar,
|
|
MaybeActivationPtr, GoalInfo0, BindProcStaticVarGoal, Goal0, Goal) :-
|
|
(
|
|
MaybeActivationPtr = yes(ActivationPtr1),
|
|
generate_deep_det_call(ModuleInfo, "det_call_port_code_sr", 4,
|
|
[ProcStaticVar, TopCSD, MiddleCSD, ActivationPtr1],
|
|
[TopCSD, MiddleCSD, ActivationPtr1], CallPortCode0),
|
|
goal_add_feature(feature_save_deep_excp_vars,
|
|
CallPortCode0, CallPortCode),
|
|
generate_deep_det_call(ModuleInfo, "det_exit_port_code_sr", 3,
|
|
[TopCSD, MiddleCSD, ActivationPtr1], [], ExitPortCode)
|
|
;
|
|
MaybeActivationPtr = no,
|
|
generate_deep_det_call(ModuleInfo, "det_call_port_code_ac", 3,
|
|
[ProcStaticVar, TopCSD, MiddleCSD],
|
|
[TopCSD, MiddleCSD], CallPortCode0),
|
|
goal_add_feature(feature_save_deep_excp_vars,
|
|
CallPortCode0, CallPortCode),
|
|
generate_deep_det_call(ModuleInfo, "det_exit_port_code_ac", 2,
|
|
[TopCSD, MiddleCSD], [], ExitPortCode)
|
|
),
|
|
|
|
make_impure(GoalInfo0, GoalInfo),
|
|
GoalExpr = conj(plain_conj, [
|
|
BindProcStaticVarGoal,
|
|
CallPortCode,
|
|
Goal0,
|
|
ExitPortCode
|
|
]),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo).
|
|
|
|
% Wrap the goal for a semidet procedure.
|
|
%
|
|
% If changing this transformation be sure to change original_root/3 in
|
|
% deep_profiler/program_represenentation_utils.m.
|
|
%
|
|
:- pred build_semi_proc_body(module_info::in, prog_var::in, prog_var::in,
|
|
prog_var::in, maybe(prog_var)::in, hlds_goal_info::in, hlds_goal::in,
|
|
hlds_goal::in, hlds_goal::out) is det.
|
|
|
|
build_semi_proc_body(ModuleInfo, TopCSD, MiddleCSD, ProcStaticVar,
|
|
MaybeActivationPtr, GoalInfo0, BindProcStaticVarGoal, Goal0, Goal) :-
|
|
(
|
|
MaybeActivationPtr = yes(ActivationPtr1),
|
|
generate_deep_det_call(ModuleInfo, "semi_call_port_code_sr", 4,
|
|
[ProcStaticVar, TopCSD, MiddleCSD, ActivationPtr1],
|
|
[TopCSD, MiddleCSD, ActivationPtr1], CallPortCode0),
|
|
goal_add_feature(feature_save_deep_excp_vars,
|
|
CallPortCode0, CallPortCode),
|
|
generate_deep_det_call(ModuleInfo, "semi_exit_port_code_sr", 3,
|
|
[TopCSD, MiddleCSD, ActivationPtr1], [], ExitPortCode),
|
|
generate_deep_call(ModuleInfo, "semi_fail_port_code_sr", 3,
|
|
[TopCSD, MiddleCSD, ActivationPtr1], maybe.no, detism_failure,
|
|
FailPortCode),
|
|
NewNonlocals =
|
|
set_of_var.list_to_set([TopCSD, MiddleCSD, ActivationPtr1])
|
|
;
|
|
MaybeActivationPtr = no,
|
|
generate_deep_det_call(ModuleInfo, "semi_call_port_code_ac", 3,
|
|
[ProcStaticVar, TopCSD, MiddleCSD],
|
|
[TopCSD, MiddleCSD], CallPortCode0),
|
|
goal_add_feature(feature_save_deep_excp_vars,
|
|
CallPortCode0, CallPortCode),
|
|
generate_deep_det_call(ModuleInfo, "semi_exit_port_code_ac", 2,
|
|
[TopCSD, MiddleCSD], [], ExitPortCode),
|
|
generate_deep_call(ModuleInfo, "semi_fail_port_code_ac", 2,
|
|
[TopCSD, MiddleCSD], maybe.no, detism_failure, FailPortCode),
|
|
NewNonlocals = set_of_var.list_to_set([TopCSD, MiddleCSD])
|
|
),
|
|
|
|
ExitConjGoalInfo = goal_info_add_nonlocals_make_impure(GoalInfo0,
|
|
NewNonlocals),
|
|
|
|
make_impure(GoalInfo0, GoalInfo),
|
|
GoalExpr = conj(plain_conj, [
|
|
BindProcStaticVarGoal,
|
|
CallPortCode,
|
|
hlds_goal(
|
|
disj([
|
|
hlds_goal(conj(plain_conj, [Goal0, ExitPortCode]),
|
|
ExitConjGoalInfo),
|
|
FailPortCode
|
|
]),
|
|
ExitConjGoalInfo)
|
|
]),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo).
|
|
|
|
:- pred build_non_proc_body(module_info::in, prog_var::in, prog_var::in,
|
|
prog_var::in, maybe(prog_var)::in, prog_var::in, hlds_goal_info::in,
|
|
hlds_goal::in, hlds_goal::in, hlds_goal::out) is det.
|
|
|
|
build_non_proc_body(ModuleInfo, TopCSD, MiddleCSD, ProcStaticVar,
|
|
MaybeOldActivationPtr, NewOutermostProcDyn, GoalInfo0,
|
|
BindProcStaticVarGoal, Goal0, Goal) :-
|
|
(
|
|
MaybeOldActivationPtr = yes(OldOutermostProcDyn2),
|
|
generate_deep_det_call(ModuleInfo, "non_call_port_code_sr", 5,
|
|
[ProcStaticVar, TopCSD, MiddleCSD,
|
|
OldOutermostProcDyn2, NewOutermostProcDyn],
|
|
[TopCSD, MiddleCSD, OldOutermostProcDyn2, NewOutermostProcDyn],
|
|
CallPortCode0),
|
|
goal_add_feature(feature_save_deep_excp_vars,
|
|
CallPortCode0, CallPortCode),
|
|
generate_deep_det_call(ModuleInfo, "non_exit_port_code_sr", 3,
|
|
[TopCSD, MiddleCSD, OldOutermostProcDyn2], [],
|
|
ExitPortCode),
|
|
generate_deep_call(ModuleInfo, "non_fail_port_code_sr", 3,
|
|
[TopCSD, MiddleCSD, OldOutermostProcDyn2], maybe.no,
|
|
detism_failure, FailPortCode),
|
|
generate_deep_call(ModuleInfo, "non_redo_port_code_sr", 2,
|
|
[MiddleCSD, NewOutermostProcDyn], maybe.no,
|
|
detism_failure, RedoPortCode0),
|
|
NewNonlocals =
|
|
set_of_var.list_to_set([TopCSD, MiddleCSD, OldOutermostProcDyn2])
|
|
;
|
|
MaybeOldActivationPtr = no,
|
|
generate_deep_det_call(ModuleInfo, "non_call_port_code_ac", 4,
|
|
[ProcStaticVar, TopCSD, MiddleCSD, NewOutermostProcDyn],
|
|
[TopCSD, MiddleCSD, NewOutermostProcDyn],
|
|
CallPortCode0),
|
|
goal_add_feature(feature_save_deep_excp_vars,
|
|
CallPortCode0, CallPortCode),
|
|
generate_deep_det_call(ModuleInfo, "non_exit_port_code_ac", 2,
|
|
[TopCSD, MiddleCSD], [], ExitPortCode),
|
|
generate_deep_call(ModuleInfo, "non_fail_port_code_ac", 2,
|
|
[TopCSD, MiddleCSD], maybe.no, detism_failure, FailPortCode),
|
|
generate_deep_call(ModuleInfo, "non_redo_port_code_ac", 2,
|
|
[MiddleCSD, NewOutermostProcDyn], maybe.no,
|
|
detism_failure, RedoPortCode0),
|
|
NewNonlocals = set_of_var.list_to_set([TopCSD, MiddleCSD])
|
|
),
|
|
|
|
RedoPortCode0 = hlds_goal(RedoPortExpr, RedoPortGoalInfo0),
|
|
goal_info_add_feature(feature_preserve_backtrack_into,
|
|
RedoPortGoalInfo0, RedoPortGoalInfo),
|
|
RedoPortCode = hlds_goal(RedoPortExpr, RedoPortGoalInfo),
|
|
|
|
% Even though the procedure has a model_non interface determinism, the
|
|
% actual determinism of its original body goal may have been at_most once.
|
|
% However, the exit/redo disjunction we insert into the procedure body
|
|
% means that the procedure body does actually leave a nondet stack frame
|
|
% when it succeeds, and its determinism must be adjusted accordingly.
|
|
%
|
|
Detism0 = goal_info_get_determinism(GoalInfo0),
|
|
determinism_components(Detism0, CanFail, _),
|
|
determinism_components(Detism, CanFail, at_most_many),
|
|
goal_info_set_determinism(Detism, GoalInfo0, GoalInfo1),
|
|
|
|
set_of_var.insert(NewOutermostProcDyn, NewNonlocals, ExitRedoNonLocals),
|
|
ExitRedoGoalInfo = impure_reachable_init_goal_info(ExitRedoNonLocals,
|
|
detism_multi),
|
|
|
|
CallExitRedoGoalInfo = goal_info_add_nonlocals_make_impure(GoalInfo1,
|
|
ExitRedoNonLocals),
|
|
|
|
make_impure(GoalInfo1, GoalInfo),
|
|
GoalExpr = conj(plain_conj, [
|
|
BindProcStaticVarGoal,
|
|
CallPortCode,
|
|
hlds_goal(
|
|
disj([
|
|
hlds_goal(
|
|
conj(plain_conj, [
|
|
Goal0,
|
|
hlds_goal(
|
|
disj([
|
|
ExitPortCode,
|
|
RedoPortCode
|
|
]),
|
|
ExitRedoGoalInfo)
|
|
]),
|
|
CallExitRedoGoalInfo),
|
|
FailPortCode
|
|
]),
|
|
CallExitRedoGoalInfo)
|
|
]),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred deep_prof_transform_goal(hlds_goal::in, hlds_goal::out,
|
|
bool::out, deep_info::in, deep_info::out) is det.
|
|
|
|
deep_prof_transform_goal(Goal0, Goal, AddedImpurity, !DeepInfo) :-
|
|
Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
|
|
goal_info_set_mdprof_inst(goal_is_not_mdprof_inst, GoalInfo0, GoalInfo1),
|
|
Goal1 = hlds_goal(GoalExpr0, GoalInfo1),
|
|
(
|
|
GoalExpr0 = plain_call(_, _, _, BuiltinState, _, _),
|
|
(
|
|
BuiltinState = not_builtin,
|
|
deep_prof_wrap_call(Goal1, Goal, !DeepInfo),
|
|
AddedImpurity = yes
|
|
;
|
|
BuiltinState = inline_builtin,
|
|
Goal = Goal1,
|
|
AddedImpurity = no
|
|
)
|
|
;
|
|
GoalExpr0 = generic_call(GenericCall, _, _, _, _),
|
|
(
|
|
( GenericCall = higher_order(_, _, _, _)
|
|
; GenericCall = class_method(_, _, _, _)
|
|
),
|
|
deep_prof_wrap_call(Goal1, Goal, !DeepInfo),
|
|
AddedImpurity = yes
|
|
;
|
|
( GenericCall = event_call(_)
|
|
; GenericCall = cast(_)
|
|
),
|
|
Goal = Goal1,
|
|
AddedImpurity = no
|
|
)
|
|
;
|
|
GoalExpr0 = call_foreign_proc(Attrs, _, _, _, _, _, _),
|
|
MayCallMercury = get_may_call_mercury(Attrs),
|
|
(
|
|
MayCallMercury = proc_may_call_mercury,
|
|
deep_prof_wrap_foreign_code(Goal1, Goal, !DeepInfo),
|
|
AddedImpurity = yes
|
|
;
|
|
MayCallMercury = proc_will_not_call_mercury,
|
|
Goal = Goal1,
|
|
AddedImpurity = no
|
|
)
|
|
;
|
|
GoalExpr0 = unify(_, _, _, _, _),
|
|
Goal = Goal1,
|
|
AddedImpurity = no
|
|
;
|
|
GoalExpr0 = conj(ConjType, Goals0),
|
|
deep_prof_transform_conj(ConjType, Goals0, Goals, AddedImpurity,
|
|
!DeepInfo),
|
|
add_impurity_if_needed(AddedImpurity, GoalInfo1, GoalInfo),
|
|
GoalExpr = conj(ConjType, Goals),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo)
|
|
;
|
|
GoalExpr0 = disj(Goals0),
|
|
deep_prof_transform_disj(Goals0, Goals, AddedImpurity, !DeepInfo),
|
|
add_impurity_if_needed(AddedImpurity, GoalInfo1, GoalInfo),
|
|
GoalExpr = disj(Goals),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo)
|
|
;
|
|
GoalExpr0 = switch(Var, CanFail, Cases0),
|
|
deep_prof_transform_switch(Cases0, Cases, AddedImpurity, !DeepInfo),
|
|
add_impurity_if_needed(AddedImpurity, GoalInfo1, GoalInfo),
|
|
GoalExpr = switch(Var, CanFail, Cases),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo)
|
|
;
|
|
GoalExpr0 = negation(SubGoal0),
|
|
deep_prof_transform_goal(SubGoal0, SubGoal, AddedImpurity, !DeepInfo),
|
|
add_impurity_if_needed(AddedImpurity, GoalInfo1, GoalInfo),
|
|
GoalExpr = negation(SubGoal),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo)
|
|
;
|
|
GoalExpr0 = if_then_else(IVars, Cond0, Then0, Else0),
|
|
deep_prof_transform_goal(Cond0, Cond, AddedImpurityC, !DeepInfo),
|
|
deep_prof_transform_goal(Then0, Then, AddedImpurityT, !DeepInfo),
|
|
deep_prof_transform_goal(Else0, Else, AddedImpurityE, !DeepInfo),
|
|
( if
|
|
( AddedImpurityC = yes
|
|
; AddedImpurityT = yes
|
|
; AddedImpurityE = yes
|
|
)
|
|
then
|
|
AddedImpurity = yes
|
|
else
|
|
AddedImpurity = no
|
|
),
|
|
add_impurity_if_needed(AddedImpurity, GoalInfo1, GoalInfo),
|
|
GoalExpr = if_then_else(IVars, Cond, Then, Else),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo)
|
|
;
|
|
GoalExpr0 = scope(Reason0, SubGoal0),
|
|
SubGoal0 = hlds_goal(_, InnerInfo),
|
|
OuterDetism = goal_info_get_determinism(GoalInfo1),
|
|
InnerDetism = goal_info_get_determinism(InnerInfo),
|
|
( if InnerDetism = OuterDetism then
|
|
Reason = Reason0,
|
|
AddForceCommit = no
|
|
else
|
|
% Given a subgoal containing both at_most_many code and impure
|
|
% code, determinism analysis will remove the `scope' wrapped
|
|
% around that subgoal if it is allowed to. If we get here, then
|
|
% the subgoal inside the `scope' contains at_most_many code
|
|
% (which means that removing the scope will change its determinism)
|
|
% and the deep profiling transformation will make it impure
|
|
% as well.
|
|
|
|
( if Reason0 = commit(_) then
|
|
Reason = commit(force_pruning),
|
|
AddForceCommit = no
|
|
else
|
|
Reason = Reason0,
|
|
AddForceCommit = yes
|
|
)
|
|
),
|
|
( if
|
|
Reason = from_ground_term(_, FGT),
|
|
( FGT = from_ground_term_construct
|
|
; FGT = from_ground_term_deconstruct
|
|
)
|
|
then
|
|
% We must annotate the scope goal and its children with a default
|
|
% deep profiling information structure, this is required by the
|
|
% coverage profiling transformation.
|
|
transform_all_goals(deep_prof_mark_goal_as_not_mdprof_inst,
|
|
SubGoal0, SubGoal),
|
|
AddedImpurity = no
|
|
else
|
|
deep_prof_transform_goal(SubGoal0, SubGoal, AddedImpurity,
|
|
!DeepInfo)
|
|
),
|
|
add_impurity_if_needed(AddedImpurity, GoalInfo1, GoalInfo),
|
|
(
|
|
AddForceCommit = no,
|
|
Goal = hlds_goal(scope(Reason, SubGoal), GoalInfo)
|
|
;
|
|
AddForceCommit = yes,
|
|
goal_info_set_mdprof_inst(goal_is_mdprof_inst, GoalInfo,
|
|
InnerGoalInfo),
|
|
InnerGoal = hlds_goal(scope(Reason, SubGoal), InnerGoalInfo),
|
|
Goal = hlds_goal(scope(commit(force_pruning), InnerGoal), GoalInfo)
|
|
)
|
|
;
|
|
GoalExpr0 = shorthand(_),
|
|
unexpected($pred, "shorthand")
|
|
).
|
|
|
|
:- pred deep_prof_mark_goal_as_not_mdprof_inst(hlds_goal::in, hlds_goal::out)
|
|
is det.
|
|
|
|
deep_prof_mark_goal_as_not_mdprof_inst(Goal0, Goal) :-
|
|
Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
|
|
goal_info_set_mdprof_inst(goal_is_not_mdprof_inst, GoalInfo0, GoalInfo),
|
|
Goal = hlds_goal(GoalExpr0, GoalInfo).
|
|
|
|
:- pred deep_prof_transform_conj(conj_type::in,
|
|
list(hlds_goal)::in, list(hlds_goal)::out, bool::out,
|
|
deep_info::in, deep_info::out) is det.
|
|
|
|
deep_prof_transform_conj(_, [], [], no, !DeepInfo).
|
|
deep_prof_transform_conj(ConjType, [Goal0 | Goals0], Goals,
|
|
AddedImpurity, !DeepInfo) :-
|
|
deep_prof_transform_goal(Goal0, Goal, AddedImpurityFirst, !DeepInfo),
|
|
deep_prof_transform_conj(ConjType, Goals0, TailGoals,
|
|
AddedImpurityLater, !DeepInfo),
|
|
Goal = hlds_goal(GoalExpr, _),
|
|
( if
|
|
GoalExpr = conj(plain_conj, Conjuncts),
|
|
ConjType = plain_conj
|
|
then
|
|
Goals = Conjuncts ++ TailGoals
|
|
else
|
|
Goals = [Goal | TailGoals]
|
|
),
|
|
bool.or(AddedImpurityFirst, AddedImpurityLater, AddedImpurity).
|
|
|
|
:- pred deep_prof_transform_disj(list(hlds_goal)::in, list(hlds_goal)::out,
|
|
bool::out, deep_info::in, deep_info::out) is det.
|
|
|
|
deep_prof_transform_disj([], [], no, !DeepInfo).
|
|
deep_prof_transform_disj([Goal0 | Goals0], [Goal | Goals],
|
|
AddedImpurity, !DeepInfo) :-
|
|
deep_prof_transform_goal(Goal0, Goal, AddedImpurityFirst, !DeepInfo),
|
|
deep_prof_transform_disj(Goals0, Goals, AddedImpurityLater,
|
|
!DeepInfo),
|
|
bool.or(AddedImpurityFirst, AddedImpurityLater, AddedImpurity).
|
|
|
|
:- pred deep_prof_transform_switch(list(case)::in, list(case)::out, bool::out,
|
|
deep_info::in, deep_info::out) is det.
|
|
|
|
deep_prof_transform_switch([], [], no, !DeepInfo).
|
|
deep_prof_transform_switch([Case0 | Cases0], [Case | Cases], AddedImpurity,
|
|
!DeepInfo) :-
|
|
Case0 = case(MainConsId, OtherConsIds, Goal0),
|
|
deep_prof_transform_goal(Goal0, Goal, AddedImpurityFirst, !DeepInfo),
|
|
Case = case(MainConsId, OtherConsIds, Goal),
|
|
deep_prof_transform_switch(Cases0, Cases,
|
|
AddedImpurityLater, !DeepInfo),
|
|
bool.or(AddedImpurityFirst, AddedImpurityLater, AddedImpurity).
|
|
|
|
:- pred deep_prof_wrap_call(hlds_goal::in, hlds_goal::out,
|
|
deep_info::in, deep_info::out) is det.
|
|
|
|
deep_prof_wrap_call(Goal0, Goal, !DeepInfo) :-
|
|
Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
|
|
GoalId = goal_info_get_goal_id(GoalInfo0),
|
|
ContainingGoalMap = !.DeepInfo ^ deep_containing_goal_map,
|
|
GoalPath = goal_id_to_forward_path(ContainingGoalMap, GoalId),
|
|
|
|
ModuleInfo = !.DeepInfo ^ deep_module_info,
|
|
GoalFeatures = goal_info_get_features(GoalInfo0),
|
|
goal_info_remove_feature(feature_deep_self_tail_rec_call,
|
|
GoalInfo0, GoalInfo1),
|
|
make_impure(GoalInfo1, GoalInfo2),
|
|
goal_info_set_mdprof_inst(goal_is_mdprof_inst, GoalInfo2,
|
|
MdprofInstGoalInfo),
|
|
|
|
% We need to make the call itself impure. If we didn't do so,
|
|
% then simplify could eliminate the goal (e.g. if it was a duplicate call).
|
|
% The result would be a prepare_for_{...}_call whose execution
|
|
% is not followed by the execution of the call port code of the callee.
|
|
% This would leave the MR_csd_callee_ptr field NULL, which violates
|
|
% invariants of the deep profiling tree (which allows this field to be
|
|
% NULL only temporarily, between the prepare_for_{...}_call and the
|
|
% call port code).
|
|
Goal1 = hlds_goal(GoalExpr0, GoalInfo2),
|
|
|
|
SiteNumCounter0 = !.DeepInfo ^ deep_site_num_counter,
|
|
counter.allocate(SiteNum, SiteNumCounter0, SiteNumCounter),
|
|
VarTable0 = !.DeepInfo ^ deep_var_table,
|
|
generate_var_int("SiteNum", SiteNumVar, VarTable0, VarTable1),
|
|
generate_deep_const_unify(some_int_const(int_const(SiteNum)),
|
|
SiteNumVar, SiteNumVarGoal),
|
|
!DeepInfo ^ deep_var_table := VarTable1,
|
|
!DeepInfo ^ deep_site_num_counter := SiteNumCounter,
|
|
|
|
Context = goal_info_get_context(GoalInfo0),
|
|
FileName0 = term_context.context_file(Context),
|
|
LineNumber = term_context.context_line(Context),
|
|
compress_filename(!.DeepInfo, FileName0, FileName),
|
|
CallKind = classify_call(ModuleInfo, GoalExpr0),
|
|
(
|
|
CallKind = call_class_normal(PredProcId),
|
|
( if set.member(feature_deep_self_tail_rec_call, GoalFeatures) then
|
|
generate_deep_det_call(ModuleInfo, "prepare_for_tail_call", 1,
|
|
[SiteNumVar], [], PrepareGoal)
|
|
else
|
|
generate_deep_det_call(ModuleInfo, "prepare_for_normal_call", 1,
|
|
[SiteNumVar], [], PrepareGoal)
|
|
),
|
|
PredProcId = proc(PredId, ProcId),
|
|
TypeSubst = compute_type_subst(GoalExpr0, !.DeepInfo),
|
|
MaybeRecInfo = !.DeepInfo ^ deep_maybe_rec_info,
|
|
( if
|
|
MaybeRecInfo = yes(RecInfo1),
|
|
RecInfo1 ^ dri_role = deep_prof_inner_proc(OuterPredProcId),
|
|
PredProcId = !.DeepInfo ^ deep_pred_proc_id
|
|
then
|
|
OuterPredProcId = proc(OuterPredId, OuterProcId),
|
|
RttiProcLabel = make_rtti_proc_label(ModuleInfo,
|
|
OuterPredId, OuterProcId)
|
|
else if
|
|
MaybeRecInfo = yes(RecInfo2),
|
|
RecInfo2 ^ dri_role = deep_prof_outer_proc(InnerPredProcId),
|
|
PredProcId = InnerPredProcId
|
|
then
|
|
OuterPredProcId = !.DeepInfo ^ deep_pred_proc_id,
|
|
OuterPredProcId = proc(OuterPredId, OuterProcId),
|
|
RttiProcLabel = make_rtti_proc_label(ModuleInfo,
|
|
OuterPredId, OuterProcId)
|
|
else
|
|
RttiProcLabel = make_rtti_proc_label(ModuleInfo, PredId, ProcId)
|
|
),
|
|
CallSite = normal_call(RttiProcLabel, TypeSubst,
|
|
FileName, LineNumber, GoalPath),
|
|
Goal2 = Goal1
|
|
;
|
|
CallKind = call_class_special(_PredProcId, TypeInfoVar),
|
|
generate_deep_det_call(ModuleInfo, "prepare_for_special_call", 2,
|
|
[SiteNumVar, TypeInfoVar], [], PrepareGoal),
|
|
CallSite = special_call(FileName, LineNumber, GoalPath),
|
|
Goal2 = Goal1
|
|
;
|
|
CallKind = call_class_generic(Generic),
|
|
(
|
|
Generic = higher_order(ClosureVar, _, _, _),
|
|
generate_deep_det_call(ModuleInfo, "prepare_for_ho_call", 2,
|
|
[SiteNumVar, ClosureVar], [], PrepareGoal),
|
|
CallSite = higher_order_call(FileName, LineNumber, GoalPath)
|
|
;
|
|
Generic = class_method(TypeClassInfoVar,
|
|
method_proc_num(MethodNum), _, _),
|
|
VarTable2 = !.DeepInfo ^ deep_var_table,
|
|
generate_var_int("MethodNum", MethodNumVar, VarTable2, VarTable3),
|
|
!DeepInfo ^ deep_var_table := VarTable3,
|
|
generate_deep_const_unify(some_int_const(int_const(MethodNum)),
|
|
MethodNumVar, MethodNumVarGoal),
|
|
generate_deep_det_call(ModuleInfo, "prepare_for_method_call", 3,
|
|
[SiteNumVar, TypeClassInfoVar, MethodNumVar],
|
|
[], PrepareCallGoal),
|
|
PrepareCallGoal = hlds_goal(_, PrepareCallGoalInfo),
|
|
PrepareGoalExpr = conj(plain_conj,
|
|
[MethodNumVarGoal, PrepareCallGoal]),
|
|
PrepareGoal = hlds_goal(PrepareGoalExpr, PrepareCallGoalInfo),
|
|
CallSite = method_call(FileName, LineNumber, GoalPath)
|
|
;
|
|
Generic = event_call(_),
|
|
unexpected($pred, "event_call")
|
|
;
|
|
Generic = cast(_),
|
|
unexpected($pred, "cast")
|
|
),
|
|
GoalCodeModel = goal_info_get_code_model(GoalInfo0),
|
|
module_info_get_globals(ModuleInfo, Globals),
|
|
globals.lookup_bool_option(Globals, use_zeroing_for_ho_cycles,
|
|
UseZeroing),
|
|
(
|
|
UseZeroing = yes,
|
|
deep_prof_transform_higher_order_call(Globals, GoalCodeModel,
|
|
Goal1, Goal2, !DeepInfo)
|
|
;
|
|
UseZeroing = no,
|
|
Goal2 = Goal1
|
|
)
|
|
),
|
|
|
|
!DeepInfo ^ deep_call_sites :=
|
|
cord.snoc(!.DeepInfo ^ deep_call_sites, CallSite),
|
|
( if
|
|
set.member(feature_deep_self_tail_rec_call, GoalFeatures),
|
|
!.DeepInfo ^ deep_maybe_rec_info = yes(RecInfo),
|
|
RecInfo ^ dri_role = deep_prof_outer_proc(_)
|
|
then
|
|
VisSCC = RecInfo ^ dri_visible_scc,
|
|
MiddleCSD = !.DeepInfo ^ deep_current_csd,
|
|
(
|
|
VisSCC = [],
|
|
CallGoals = [],
|
|
ExitGoals = [],
|
|
FailGoals = [],
|
|
SaveRestoreVars = []
|
|
;
|
|
VisSCC = [SCCmember],
|
|
generate_recursion_counter_saves_and_restores(
|
|
SCCmember ^ rec_call_sites, MiddleCSD,
|
|
CallGoals, ExitGoals, FailGoals, SaveRestoreVars, !DeepInfo)
|
|
;
|
|
VisSCC = [_, _ | _],
|
|
unexpected($pred, "multi-procedure SCCs not yet implemented")
|
|
),
|
|
|
|
CodeModel = goal_info_get_code_model(GoalInfo0),
|
|
(
|
|
CodeModel = model_det,
|
|
Goals =
|
|
CallGoals ++ [SiteNumVarGoal, PrepareGoal, Goal2] ++ ExitGoals,
|
|
GoalExpr = conj(plain_conj, Goals)
|
|
;
|
|
( CodeModel = model_semi
|
|
; CodeModel = model_non
|
|
),
|
|
ExtraVars = set_of_var.list_to_set([MiddleCSD | SaveRestoreVars]),
|
|
WrappedGoalGoalInfo0 =
|
|
goal_info_add_nonlocals_make_impure(MdprofInstGoalInfo,
|
|
ExtraVars),
|
|
goal_info_set_mdprof_inst(goal_is_mdprof_inst,
|
|
WrappedGoalGoalInfo0, WrappedGoalGoalInfo),
|
|
|
|
ReturnFailsGoalInfo0 =
|
|
impure_unreachable_init_goal_info(ExtraVars, detism_failure),
|
|
goal_info_set_mdprof_inst(goal_is_mdprof_inst,
|
|
ReturnFailsGoalInfo0, ReturnFailsGoalInfo),
|
|
|
|
FailGoalInfo0 = fail_goal_info,
|
|
goal_info_set_mdprof_inst(goal_is_mdprof_inst,
|
|
FailGoalInfo0, FailGoalInfo),
|
|
FailGoal = hlds_goal(disj([]), FailGoalInfo),
|
|
|
|
FailGoalsAndFail = FailGoals ++ [FailGoal],
|
|
|
|
DisjGoalExpr = disj([
|
|
hlds_goal(
|
|
conj(plain_conj,
|
|
[SiteNumVarGoal, PrepareGoal, Goal2 | ExitGoals]),
|
|
WrappedGoalGoalInfo),
|
|
hlds_goal(
|
|
conj(plain_conj, FailGoalsAndFail),
|
|
ReturnFailsGoalInfo)
|
|
]),
|
|
DisjGoal = hlds_goal(DisjGoalExpr, WrappedGoalGoalInfo),
|
|
Goals = CallGoals ++ [DisjGoal],
|
|
GoalExpr = conj(plain_conj, Goals)
|
|
)
|
|
else
|
|
GoalExpr = conj(plain_conj, [SiteNumVarGoal, PrepareGoal, Goal2])
|
|
),
|
|
Goal = hlds_goal(GoalExpr, MdprofInstGoalInfo).
|
|
|
|
:- pred deep_prof_transform_higher_order_call(globals::in, code_model::in,
|
|
hlds_goal::in, hlds_goal::out, deep_info::in, deep_info::out) is det.
|
|
|
|
deep_prof_transform_higher_order_call(Globals, CodeModel, Goal0, Goal,
|
|
!DeepInfo) :-
|
|
some [!VarTable] (
|
|
!:VarTable = !.DeepInfo ^ deep_var_table,
|
|
|
|
generate_var_c_ptr("SavedPtr", SavedPtrVar, !VarTable),
|
|
|
|
globals.lookup_bool_option(Globals, use_activation_counts,
|
|
UseActivationCounts),
|
|
(
|
|
UseActivationCounts = yes,
|
|
|
|
generate_var_int("SavedCounter", SavedCountVar, !VarTable),
|
|
ExtraNonLocals =
|
|
set_of_var.list_to_set([SavedCountVar, SavedPtrVar]),
|
|
|
|
generate_deep_det_call(!.DeepInfo ^ deep_module_info,
|
|
"save_and_zero_activation_info_ac", 2,
|
|
[SavedCountVar, SavedPtrVar],
|
|
[SavedCountVar, SavedPtrVar], SaveStuff),
|
|
generate_deep_det_call(!.DeepInfo ^ deep_module_info,
|
|
"reset_activation_info_ac", 2,
|
|
[SavedCountVar, SavedPtrVar], [], RestoreStuff),
|
|
generate_deep_det_call(!.DeepInfo ^ deep_module_info,
|
|
"rezero_activation_info_ac", 0,
|
|
[], [], ReZeroStuff)
|
|
;
|
|
UseActivationCounts = no,
|
|
|
|
ExtraNonLocals = set_of_var.make_singleton(SavedPtrVar),
|
|
|
|
generate_deep_det_call(!.DeepInfo ^ deep_module_info,
|
|
"save_and_zero_activation_info_sr", 1,
|
|
[SavedPtrVar], [SavedPtrVar], SaveStuff),
|
|
generate_deep_det_call(!.DeepInfo ^ deep_module_info,
|
|
"reset_activation_info_sr", 1,
|
|
[SavedPtrVar], [], RestoreStuff),
|
|
generate_deep_det_call(!.DeepInfo ^ deep_module_info,
|
|
"rezero_activation_info_sr", 0,
|
|
[], [], ReZeroStuff)
|
|
),
|
|
|
|
!DeepInfo ^ deep_var_table := !.VarTable
|
|
),
|
|
|
|
Goal0 = hlds_goal(_, GoalInfo0),
|
|
ExtGoalInfo0 = goal_info_add_nonlocals_make_impure(GoalInfo0,
|
|
ExtraNonLocals),
|
|
goal_info_set_mdprof_inst(goal_is_mdprof_inst, ExtGoalInfo0, ExtGoalInfo),
|
|
|
|
% XXX We should build up NoBindExtGoalInfo from scratch.
|
|
instmap_delta_init_reachable(EmptyDelta),
|
|
goal_info_set_instmap_delta(EmptyDelta, ExtGoalInfo, NoBindExtGoalInfo),
|
|
|
|
FailGoalInfo0 = fail_goal_info,
|
|
goal_info_set_mdprof_inst(goal_is_mdprof_inst,
|
|
FailGoalInfo0, FailGoalInfo),
|
|
FailGoal = hlds_goal(disj([]), FailGoalInfo),
|
|
|
|
RestoreFailGoalInfo0 = impure_unreachable_init_goal_info(ExtraNonLocals,
|
|
detism_failure),
|
|
goal_info_set_mdprof_inst(goal_is_mdprof_inst,
|
|
RestoreFailGoalInfo0, RestoreFailGoalInfo),
|
|
|
|
RezeroFailGoalInfo0 = impure_unreachable_init_goal_info(set_of_var.init,
|
|
detism_failure),
|
|
goal_info_set_mdprof_inst(goal_is_mdprof_inst,
|
|
RezeroFailGoalInfo0, RezeroFailGoalInfo),
|
|
|
|
make_impure(GoalInfo0, GoalInfo),
|
|
(
|
|
CodeModel = model_det,
|
|
GoalExpr = conj(plain_conj, [SaveStuff, Goal0, RestoreStuff]),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo)
|
|
;
|
|
CodeModel = model_semi,
|
|
GoalExpr = conj(plain_conj, [
|
|
SaveStuff,
|
|
hlds_goal(
|
|
disj([
|
|
hlds_goal(
|
|
conj(plain_conj, [Goal0, RestoreStuff]),
|
|
ExtGoalInfo),
|
|
hlds_goal(
|
|
conj(plain_conj, [RestoreStuff, FailGoal]),
|
|
RestoreFailGoalInfo)
|
|
]),
|
|
ExtGoalInfo)
|
|
]),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo)
|
|
;
|
|
CodeModel = model_non,
|
|
GoalExpr = conj(plain_conj, [
|
|
SaveStuff,
|
|
hlds_goal(
|
|
disj([
|
|
hlds_goal(
|
|
conj(plain_conj, [
|
|
Goal0,
|
|
hlds_goal(
|
|
disj([
|
|
RestoreStuff,
|
|
hlds_goal(
|
|
conj(plain_conj,
|
|
[ReZeroStuff, FailGoal]),
|
|
RezeroFailGoalInfo)
|
|
]),
|
|
NoBindExtGoalInfo)
|
|
]),
|
|
ExtGoalInfo),
|
|
hlds_goal(
|
|
conj(plain_conj, [RestoreStuff, FailGoal]),
|
|
RestoreFailGoalInfo)
|
|
]),
|
|
ExtGoalInfo)
|
|
]),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo)
|
|
).
|
|
|
|
:- pred deep_prof_wrap_foreign_code(hlds_goal::in, hlds_goal::out,
|
|
deep_info::in, deep_info::out) is det.
|
|
|
|
deep_prof_wrap_foreign_code(Goal0, Goal, !DeepInfo) :-
|
|
Goal0 = hlds_goal(_GoalExpr0, GoalInfo0),
|
|
GoalId = goal_info_get_goal_id(GoalInfo0),
|
|
ContainingGoalMap = !.DeepInfo ^ deep_containing_goal_map,
|
|
GoalPath = goal_id_to_forward_path(ContainingGoalMap, GoalId),
|
|
|
|
SiteNumCounter0 = !.DeepInfo ^ deep_site_num_counter,
|
|
counter.allocate(SiteNum, SiteNumCounter0, SiteNumCounter),
|
|
generate_var_int("SiteNum", SiteNumVar,
|
|
!.DeepInfo ^ deep_var_table, VarTable),
|
|
generate_deep_const_unify(some_int_const(int_const(SiteNum)),
|
|
SiteNumVar, SiteNumVarGoal),
|
|
|
|
ModuleInfo = !.DeepInfo ^ deep_module_info,
|
|
generate_deep_det_call(ModuleInfo, "prepare_for_callback", 1,
|
|
[SiteNumVar], [], PrepareGoal),
|
|
|
|
Context = goal_info_get_context(GoalInfo0),
|
|
FileName0 = term_context.context_file(Context),
|
|
LineNumber = term_context.context_line(Context),
|
|
compress_filename(!.DeepInfo, FileName0, FileName),
|
|
CallSite = callback(FileName, LineNumber, GoalPath),
|
|
|
|
make_impure(GoalInfo0, GoalInfo1),
|
|
goal_info_set_mdprof_inst(goal_is_mdprof_inst, GoalInfo1, GoalInfo),
|
|
GoalExpr = conj(plain_conj, [SiteNumVarGoal, PrepareGoal, Goal0]),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo),
|
|
!DeepInfo ^ deep_site_num_counter := SiteNumCounter,
|
|
!DeepInfo ^ deep_var_table := VarTable,
|
|
!DeepInfo ^ deep_call_sites :=
|
|
cord.snoc(!.DeepInfo ^ deep_call_sites, CallSite).
|
|
|
|
:- pred compress_filename(deep_info::in, string::in, string::out) is det.
|
|
|
|
compress_filename(Deep, FileName0, FileName) :-
|
|
( if FileName0 = Deep ^ deep_proc_filename then
|
|
FileName = ""
|
|
else
|
|
FileName = FileName0
|
|
).
|
|
|
|
:- type call_class
|
|
---> call_class_normal(pred_proc_id)
|
|
% For normal first order calls
|
|
|
|
; call_class_special(pred_proc_id, prog_var)
|
|
% For calls to unify/2, compare/3 and
|
|
% compare_representation/3
|
|
|
|
; call_class_generic(generic_call).
|
|
% For higher order and typeclass method calls
|
|
|
|
:- func classify_call(module_info, hlds_goal_expr) = call_class.
|
|
|
|
classify_call(ModuleInfo, Expr) = Class :-
|
|
(
|
|
Expr = plain_call(PredId, ProcId, ArgVars, _, _, _),
|
|
( if
|
|
lookup_builtin_pred_proc_id(ModuleInfo,
|
|
mercury_public_builtin_module, "unify",
|
|
pf_predicate, user_arity(2), mode_no(0), PredId, _),
|
|
ArgVars = [TypeInfoVar | _]
|
|
then
|
|
Class = call_class_special(proc(PredId, ProcId), TypeInfoVar)
|
|
else if
|
|
lookup_builtin_pred_proc_id(ModuleInfo,
|
|
mercury_public_builtin_module, "compare",
|
|
pf_predicate, user_arity(3), mode_no(0), PredId, _),
|
|
ArgVars = [TypeInfoVar | _]
|
|
then
|
|
Class = call_class_special(proc(PredId, ProcId), TypeInfoVar)
|
|
else if
|
|
lookup_builtin_pred_proc_id(ModuleInfo,
|
|
mercury_public_builtin_module,
|
|
"compare_representation", pf_predicate, user_arity(3),
|
|
mode_no(0), PredId, _),
|
|
ArgVars = [TypeInfoVar | _]
|
|
then
|
|
Class = call_class_special(proc(PredId, ProcId), TypeInfoVar)
|
|
else
|
|
Class = call_class_normal(proc(PredId, ProcId))
|
|
)
|
|
;
|
|
Expr = generic_call(Generic, _, _, _, _),
|
|
Class = call_class_generic(Generic)
|
|
;
|
|
( Expr = call_foreign_proc(_, _, _, _, _, _, _)
|
|
; Expr = unify(_, _, _, _, _)
|
|
; Expr = conj(_, _)
|
|
; Expr = disj(_)
|
|
; Expr = switch(_, _, _)
|
|
; Expr = if_then_else(_, _, _, _)
|
|
; Expr = negation(_)
|
|
; Expr = scope(_, _)
|
|
; Expr = shorthand(_)
|
|
),
|
|
unexpected($pred, "unexpected goal type")
|
|
).
|
|
|
|
:- func compute_type_subst(hlds_goal_expr, deep_info) = string.
|
|
|
|
% XXX we don't compute type substitution strings yet.
|
|
compute_type_subst(_, _) = "".
|
|
|
|
% The maximum value of N for which save_recursion_depth_N,
|
|
% restore_recursion_depth_exit_N and restore_recursion_depth_fail_N
|
|
% exist in library/profiling_builtin.m.
|
|
%
|
|
:- func max_save_restore_vector_size = int.
|
|
|
|
max_save_restore_vector_size = 9.
|
|
|
|
:- pred generate_recursion_counter_saves_and_restores(list(int)::in,
|
|
prog_var::in, list(hlds_goal)::out, list(hlds_goal)::out,
|
|
list(hlds_goal)::out, list(prog_var)::out,
|
|
deep_info::in, deep_info::out) is det.
|
|
|
|
generate_recursion_counter_saves_and_restores(CSNs, CSDVar, CallGoals,
|
|
ExitGoals, FailGoals, ExtraVars, !DeepInfo) :-
|
|
list.chunk(CSNs, max_save_restore_vector_size, CSNChunks),
|
|
generate_recursion_counter_saves_and_restores_2(CSNChunks, CSDVar,
|
|
CallGoals, ExitGoals, FailGoals, ExtraVars, !DeepInfo).
|
|
|
|
:- pred generate_recursion_counter_saves_and_restores_2(list(list(int))::in,
|
|
prog_var::in, list(hlds_goal)::out, list(hlds_goal)::out,
|
|
list(hlds_goal)::out, list(prog_var)::out,
|
|
deep_info::in, deep_info::out) is det.
|
|
|
|
generate_recursion_counter_saves_and_restores_2([], _, [], [], [], [],
|
|
!DeepInfo).
|
|
generate_recursion_counter_saves_and_restores_2([Chunk | Chunks], CSDVar,
|
|
CallGoals, ExitGoals, FailGoals, ExtraVars, !DeepInfo) :-
|
|
list.map_foldl(generate_depth_var, Chunk, DepthVars, !DeepInfo),
|
|
|
|
% We generate three separate variables to hold the constant CSN vector.
|
|
% If we used only one, the code generator would have to save its value
|
|
% on the stack when we enter the disjunction that wraps the goal.
|
|
list.length(Chunk, Length),
|
|
generate_csn_vector(Length, Chunk, CSNCallVars, CSNCallGoals, CallCellVar,
|
|
!DeepInfo),
|
|
generate_csn_vector(Length, Chunk, CSNExitVars, CSNExitGoals, ExitCellVar,
|
|
!DeepInfo),
|
|
generate_csn_vector(Length, Chunk, CSNFailVars, CSNFailGoals, FailCellVar,
|
|
!DeepInfo),
|
|
list.condense([CSNCallVars, CSNExitVars, CSNFailVars], CSNExtraVars),
|
|
|
|
CallPredName = string.format("save_recursion_depth_%d", [i(Length)]),
|
|
ExitPredName = string.format("restore_recursion_depth_exit_%d",
|
|
[i(Length)]),
|
|
FailPredName = string.format("restore_recursion_depth_fail_%d",
|
|
[i(Length)]),
|
|
ModuleInfo = !.DeepInfo ^ deep_module_info,
|
|
generate_deep_det_call(ModuleInfo, CallPredName, Length + 2,
|
|
[CSDVar, CallCellVar | DepthVars], DepthVars, CallCellGoal),
|
|
generate_deep_det_call(ModuleInfo, ExitPredName, Length + 2,
|
|
[CSDVar, ExitCellVar | DepthVars], [], ExitCellGoal),
|
|
generate_deep_det_call(ModuleInfo, FailPredName, Length + 2,
|
|
[CSDVar, FailCellVar | DepthVars], [], FailCellGoal),
|
|
|
|
generate_recursion_counter_saves_and_restores_2(Chunks, CSDVar,
|
|
TailCallGoals, TailExitGoals, TailFailGoals, TailExtraVars, !DeepInfo),
|
|
|
|
CallGoals = CSNCallGoals ++ [CallCellGoal | TailCallGoals],
|
|
ExitGoals = CSNExitGoals ++ [ExitCellGoal | TailExitGoals],
|
|
FailGoals = CSNFailGoals ++ [FailCellGoal | TailFailGoals],
|
|
ExtraVars = CSNExtraVars ++ TailExtraVars.
|
|
|
|
:- pred generate_depth_var(int::in, prog_var::out,
|
|
deep_info::in, deep_info::out) is det.
|
|
|
|
generate_depth_var(CSN, DepthVar, !DeepInfo) :-
|
|
VarTable0 = !.DeepInfo ^ deep_var_table,
|
|
VarName = string.format("Depth%d", [i(CSN)]),
|
|
generate_var_int(VarName, DepthVar, VarTable0, VarTable),
|
|
!DeepInfo ^ deep_var_table := VarTable.
|
|
|
|
:- pred generate_csn_vector(int::in, list(int)::in, list(prog_var)::out,
|
|
list(hlds_goal)::out, prog_var::out,
|
|
deep_info::in, deep_info::out) is det.
|
|
|
|
generate_csn_vector(Length, CSNs, CSNVars, UnifyGoals, CellVar, !DeepInfo) :-
|
|
( if CSNs = [CSN] then
|
|
generate_single_csn_unify(CSN, CSNVar - UnifyGoal, !DeepInfo),
|
|
CSNVars = [CSNVar],
|
|
UnifyGoals = [UnifyGoal],
|
|
CellVar = CSNVar
|
|
else
|
|
expect(Length =< max_save_restore_vector_size, $pred, "too long"),
|
|
list.map_foldl(generate_single_csn_unify, CSNs, CSNVarsGoals,
|
|
!DeepInfo),
|
|
InnerVars = assoc_list.keys(CSNVarsGoals),
|
|
InnerGoals = assoc_list.values(CSNVarsGoals),
|
|
generate_csn_vector_cell(Length, InnerVars, CellVar, CellGoal,
|
|
!DeepInfo),
|
|
CSNVars = [CellVar | InnerVars],
|
|
UnifyGoals = InnerGoals ++ [CellGoal]
|
|
).
|
|
|
|
:- pred generate_csn_vector_cell(int::in, list(prog_var)::in,
|
|
prog_var::out, hlds_goal::out, deep_info::in, deep_info::out) is det.
|
|
|
|
generate_csn_vector_cell(Length, CSNVars, CellVar, CellGoal, !DeepInfo) :-
|
|
ProfilingBuiltin = mercury_profiling_builtin_module,
|
|
CellTypeName = string.format("call_site_nums_%d", [i(Length)]),
|
|
CellTypeCtor = type_ctor(qualified(ProfilingBuiltin, CellTypeName), 0),
|
|
construct_type(CellTypeCtor, [], CellType),
|
|
CellVarEntry = vte("CSNCell", CellType, is_not_dummy_type),
|
|
VarTable0 = !.DeepInfo ^ deep_var_table,
|
|
add_var_entry(CellVarEntry, CellVar, VarTable0, VarTable),
|
|
!DeepInfo ^ deep_var_table := VarTable,
|
|
ConsId = cons(qualified(ProfilingBuiltin, CellTypeName), Length,
|
|
CellTypeCtor),
|
|
generate_deep_cell_unify(Length, ConsId, CSNVars, CellVar, CellGoal).
|
|
|
|
:- pred generate_single_csn_unify(int::in,
|
|
pair(prog_var, hlds_goal)::out, deep_info::in, deep_info::out) is det.
|
|
|
|
generate_single_csn_unify(CSN, CSNVar - UnifyGoal, !DeepInfo) :-
|
|
VarTable0 = !.DeepInfo ^ deep_var_table,
|
|
VarName = string.format("CSN%d", [i(CSN)]),
|
|
generate_var_int(VarName, CSNVar, VarTable0, VarTable),
|
|
!DeepInfo ^ deep_var_table := VarTable,
|
|
generate_deep_const_unify(some_int_const(int_const(CSN)),
|
|
CSNVar, UnifyGoal).
|
|
|
|
:- pred generate_deep_det_call(module_info::in, string::in, int::in,
|
|
list(prog_var)::in, list(prog_var)::in, hlds_goal::out) is det.
|
|
|
|
generate_deep_det_call(ModuleInfo, Name, Arity, ArgVars, OutputVars, Goal) :-
|
|
generate_deep_call(ModuleInfo, Name, Arity, ArgVars, yes(OutputVars),
|
|
detism_det, Goal).
|
|
|
|
generate_deep_call(ModuleInfo, Name, Arity, ArgVars, MaybeOutputVars, Detism,
|
|
Goal) :-
|
|
get_deep_profile_builtin_ppid(ModuleInfo, Name, Arity, PredId, ProcId),
|
|
NonLocals = set_of_var.list_to_set(ArgVars),
|
|
(
|
|
MaybeOutputVars = yes(OutputVars),
|
|
InstMapDelta = instmap_delta_bind_vars(OutputVars)
|
|
;
|
|
MaybeOutputVars = no,
|
|
instmap_delta_init_unreachable(InstMapDelta)
|
|
),
|
|
SymName = unqualified(Name),
|
|
GoalExpr = plain_call(PredId, ProcId, ArgVars, not_builtin, no, SymName),
|
|
GoalInfo1 = impure_init_goal_info(NonLocals, InstMapDelta, Detism),
|
|
goal_info_set_mdprof_inst(goal_is_mdprof_inst, GoalInfo1, GoalInfo),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo).
|
|
|
|
generate_deep_const_unify(ConsId, Var, Goal) :-
|
|
Ground = ground(shared, none_or_default_func),
|
|
UnifyMode = unify_modes_li_lf_ri_rf(free, Ground, Ground, Ground),
|
|
Unification = construct(Var, ConsId, [], [],
|
|
construct_statically(born_static), cell_is_shared,
|
|
no_construct_sub_info),
|
|
GoalExpr = unify(Var, rhs_functor(ConsId, is_not_exist_constr, []),
|
|
UnifyMode, Unification, unify_context(umc_explicit, [])),
|
|
NonLocals = set_of_var.make_singleton(Var),
|
|
InstMapDelta = instmap_delta_bind_var(Var),
|
|
goal_info_init(NonLocals, InstMapDelta, detism_det, purity_pure,
|
|
GoalInfo1),
|
|
goal_info_set_mdprof_inst(goal_is_mdprof_inst, GoalInfo1, GoalInfo),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo).
|
|
|
|
:- pred generate_deep_cell_unify(int::in, cons_id::in, list(prog_var)::in,
|
|
prog_var::in, hlds_goal::out) is det.
|
|
|
|
generate_deep_cell_unify(Length, ConsId, ArgVars, Var, Goal) :-
|
|
Ground = ground(shared, none_or_default_func),
|
|
UnifyMode = unify_modes_li_lf_ri_rf(free, Ground, Ground, Ground),
|
|
list.duplicate(Length, UnifyMode, ArgModes),
|
|
Unification = construct(Var, ConsId, ArgVars, ArgModes,
|
|
construct_statically(born_static), cell_is_shared,
|
|
no_construct_sub_info),
|
|
GoalExpr = unify(Var, rhs_functor(ConsId, is_not_exist_constr, ArgVars),
|
|
UnifyMode, Unification, unify_context(umc_explicit, [])),
|
|
NonLocals = set_of_var.list_to_set([Var | ArgVars]),
|
|
InstMapDelta = instmap_delta_bind_var(Var),
|
|
Determinism = detism_det,
|
|
goal_info_init(NonLocals, InstMapDelta, Determinism, purity_pure,
|
|
GoalInfo),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo).
|
|
|
|
:- pred maybe_generate_activation_ptr(bool::in, prog_var::in, prog_var::in,
|
|
maybe(prog_var)::out, hlds_deep_excp_vars::out,
|
|
var_table::in, var_table::out) is det.
|
|
|
|
maybe_generate_activation_ptr(UseActivationCounts, TopCSD, MiddleCSD,
|
|
MaybeActivationPtr, ExcpVars, !VarTable) :-
|
|
(
|
|
UseActivationCounts = no,
|
|
generate_var_c_ptr("ActivationPtr", ActivationPtr0, !VarTable),
|
|
MaybeActivationPtr = yes(ActivationPtr0)
|
|
;
|
|
UseActivationCounts = yes,
|
|
MaybeActivationPtr = no
|
|
),
|
|
ExcpVars = hlds_deep_excp_vars(TopCSD, MiddleCSD, MaybeActivationPtr).
|
|
|
|
:- pred generate_outermost_proc_dyns(bool::in, prog_var::in, prog_var::in,
|
|
maybe(prog_var)::out, prog_var::out, hlds_deep_excp_vars::out,
|
|
var_table::in, var_table::out) is det.
|
|
|
|
generate_outermost_proc_dyns(UseActivationCounts, TopCSD, MiddleCSD,
|
|
MaybeOldActivationPtr, NewOutermostProcDyn, ExcpVars, !VarTable) :-
|
|
(
|
|
UseActivationCounts = no,
|
|
generate_var_c_ptr("OldOutermost", OldOutermostProcDyn0, !VarTable),
|
|
MaybeOldActivationPtr = yes(OldOutermostProcDyn0)
|
|
;
|
|
UseActivationCounts = yes,
|
|
MaybeOldActivationPtr = no
|
|
),
|
|
ExcpVars = hlds_deep_excp_vars(TopCSD, MiddleCSD, MaybeOldActivationPtr),
|
|
generate_var_c_ptr("NewOutermost", NewOutermostProcDyn, !VarTable).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
get_deep_profile_builtin_ppid(ModuleInfo, Name, Arity, PredId, ProcId) :-
|
|
ModuleName = mercury_profiling_builtin_module,
|
|
module_info_get_predicate_table(ModuleInfo, PredTable),
|
|
predicate_table_lookup_pred_m_n_a(PredTable,
|
|
is_fully_qualified, ModuleName, Name, user_arity(Arity), PredIds),
|
|
(
|
|
PredIds = [],
|
|
unexpected($pred, "no pred_id")
|
|
;
|
|
PredIds = [PredId],
|
|
predicate_table_get_pred_id_table(PredTable, PredIdTable),
|
|
map.lookup(PredIdTable, PredId, PredInfo),
|
|
ProcIds = pred_info_all_procids(PredInfo),
|
|
(
|
|
ProcIds = [],
|
|
unexpected($pred, "no proc_id")
|
|
;
|
|
ProcIds = [ProcId]
|
|
;
|
|
ProcIds = [_, _ | _],
|
|
unexpected($pred, "proc_id not unique")
|
|
)
|
|
;
|
|
PredIds = [_, _ | _],
|
|
unexpected($pred, "pred_id not unique")
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred extract_deep_rec_info(maybe(deep_profile_proc_info)::in,
|
|
maybe(deep_recursion_info)::out) is det.
|
|
|
|
extract_deep_rec_info(MaybeDeepProfInfo, MaybeRecInfo) :-
|
|
(
|
|
MaybeDeepProfInfo = yes(DeepProfInfo),
|
|
DeepProfInfo = deep_profile_proc_info(MaybeRecInfo, _, _)
|
|
;
|
|
MaybeDeepProfInfo = no,
|
|
MaybeRecInfo = no
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
generate_var_int(Name, Var, !VarTable) :-
|
|
Entry = vte(Name, int_type, is_not_dummy_type),
|
|
add_var_entry(Entry, Var, !VarTable).
|
|
|
|
generate_var_c_ptr(Name, Var, !VarTable) :-
|
|
Entry = vte(Name, c_pointer_type, is_not_dummy_type),
|
|
add_var_entry(Entry, Var, !VarTable).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- end_module ll_backend.deep_profiling.
|
|
%-----------------------------------------------------------------------------%
|