Files
mercury/compiler/deep_profiling.m
Zoltan Somogyi b39a3d855f This diff makes hlds_module.m and many callers of its predicates easier to read
Estimated hours taken: 6
Branches: main

This diff makes hlds_module.m and many callers of its predicates easier to read
and to maintain, but contains no changes in algorithms whatsoever.

compiler/hlds_module.m:
	Bring (most of) this module into line with our current coding
	standards. Use predmode declarations, functions, and state variable
	syntax when appropriate. (The 'most of' is because I left the part of
	the module dealing with predicate tables alone, not wishing to cause
	a conflict for Pete.)

	Reorder arguments of predicates where necessary for the use of state
	variable syntax, and where this improves readability.

	Replace old-style lambdas with new-style lambdas or with partially
	applied named procedures.

compiler/*.m:
	Conform to the changes in hlds_module.m. This mostly means using the
	new argument orders of predicates exported by hlds_module.m, and
	switching to state variable notation.

	Replace old-style lambdas with new-style lambdas or with partially
	applied named procedures in updated code.

	Replace unnecessary occurrences of four-space indentation with
	standard indentation in updated code.

library/list.m:
library/map.m:
library/tree234.m:
	Add list__foldl4 and map__foldl3, since in some compiler modules,
	state variable notation is more convenient (and the code more
	efficient) if we don't have to bundle up several data structures
	into a tuple just to iterate over them.

	Change the fold predicates to use state variable notation.

NEWS:
	Mention the new library functions.
2003-10-31 03:27:39 +00:00

1782 lines
59 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 2001-2003 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.
%-----------------------------------------------------------------------------%
%
% 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__hlds_module.
:- import_module ll_backend__layout.
:- import_module io, list.
:- pred apply_deep_profiling_transformation(module_info::in, module_info::out,
list(layout_data)::out, io__state::di, io__state::uo) is det.
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module backend_libs__code_model.
:- import_module backend_libs__rtti.
:- import_module check_hlds__mode_util.
:- import_module check_hlds__type_util.
:- import_module hlds__hlds_data.
:- import_module hlds__hlds_goal.
:- import_module hlds__hlds_pred.
:- import_module hlds__instmap.
:- import_module hlds__quantification.
:- import_module libs__globals.
:- import_module libs__options.
:- import_module ll_backend__code_util.
:- import_module ll_backend__trace.
:- import_module parse_tree__inst.
:- import_module parse_tree__prog_data.
:- import_module parse_tree__prog_util.
:- import_module transform_hlds__dependency_graph.
:- import_module bool, int, list, assoc_list, map, require, set.
:- import_module std_util, string, term, varset, counter.
apply_deep_profiling_transformation(!ModuleInfo, ProcStatics, !IO) :-
module_info_globals(!.ModuleInfo, Globals),
globals__lookup_bool_option(Globals, deep_profile_tail_recursion,
TailRecursion),
(
TailRecursion = yes,
apply_tail_recursion_transformation(!ModuleInfo)
;
TailRecursion = no
),
module_info_predids(!.ModuleInfo, PredIds),
module_info_get_predicate_table(!.ModuleInfo, PredTable0),
predicate_table_get_preds(PredTable0, PredMap0),
list__foldl2(transform_predicate(!.ModuleInfo),
PredIds, PredMap0, PredMap, [], MaybeProcStatics),
% Remove any duplicates that resulted from
% references in inner tail recursive procedures
list__filter_map(
(pred(MaybeProcStatic::in, ProcStatic::out) is semidet :-
MaybeProcStatic = yes(ProcStatic)
), MaybeProcStatics, ProcStatics),
predicate_table_set_preds(PredTable0, PredMap, PredTable),
module_info_set_predicate_table(PredTable, !ModuleInfo).
%-----------------------------------------------------------------------------%
:- pred apply_tail_recursion_transformation(module_info::in, module_info::out)
is det.
apply_tail_recursion_transformation(ModuleInfo0, ModuleInfo) :-
module_info_ensure_dependency_info(ModuleInfo0, ModuleInfo1),
module_info_dependency_info(ModuleInfo1, DepInfo),
hlds_dependency_info_get_dependency_ordering(DepInfo, SCCs),
list__foldl(apply_tail_recursion_to_scc, SCCs,
ModuleInfo1, ModuleInfo).
:- pred apply_tail_recursion_to_scc(list(pred_proc_id)::in,
module_info::in, module_info::out) is det.
apply_tail_recursion_to_scc(SCC, ModuleInfo0, ModuleInfo) :-
% For the time being, we only look for self-tail-recursive calls.
list__foldl(apply_tail_recursion_to_proc, SCC,
ModuleInfo0, ModuleInfo).
:- pred apply_tail_recursion_to_proc(pred_proc_id::in,
module_info::in, module_info::out) is det.
apply_tail_recursion_to_proc(PredProcId, ModuleInfo0, ModuleInfo) :-
PredProcId = proc(PredId, ProcId),
module_info_preds(ModuleInfo0, PredTable0),
map__lookup(PredTable0, PredId, PredInfo0),
pred_info_arg_types(PredInfo0, Types),
pred_info_procedures(PredInfo0, ProcTable0),
map__lookup(ProcTable0, ProcId, ProcInfo0),
proc_info_goal(ProcInfo0, Goal0),
proc_info_interface_determinism(ProcInfo0, Detism),
(
determinism_components(Detism, _CanFail, SolnCount),
SolnCount \= at_most_many,
proc_info_headvars(ProcInfo0, HeadVars),
proc_info_argmodes(ProcInfo0, Modes),
find_list_of_output_args(HeadVars, Modes, Types, ModuleInfo0,
Outputs),
clone_proc_id(ProcTable0, ProcId, CloneProcId),
ClonePredProcId = proc(PredId, CloneProcId),
ApplyInfo = apply_tail_recursion_info(ModuleInfo0,
[PredProcId - ClonePredProcId], Detism, Outputs),
apply_tail_recursion_to_goal(Goal0, ApplyInfo,
Goal, no, FoundTailCall, _),
FoundTailCall = yes
->
proc_info_set_goal(Goal, ProcInfo0, ProcInfo1),
figure_out_rec_call_numbers(Goal, 0, _N, [], TailCallSites),
OrigDeepProfileInfo = deep_profile_proc_info(
outer_proc(ClonePredProcId),
[visible_scc_data(PredProcId, ClonePredProcId,
TailCallSites)]),
CloneDeepProfileInfo = deep_profile_proc_info(
inner_proc(PredProcId),
[visible_scc_data(PredProcId, ClonePredProcId,
TailCallSites)]),
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(ProcTable0, ProcId, ProcInfo, ProcTable1),
map__det_insert(ProcTable1, CloneProcId, CloneProcInfo,
ProcTable),
pred_info_set_procedures(ProcTable, PredInfo0, PredInfo),
map__det_update(PredTable0, PredId, PredInfo, PredTable),
module_info_set_preds(PredTable, ModuleInfo0, ModuleInfo)
;
ModuleInfo = ModuleInfo0
).
:- pred find_list_of_output_args(list(prog_var)::in, list(mode)::in,
list(type)::in, module_info::in, list(prog_var)::out) is det.
find_list_of_output_args(Vars, Modes, Types, ModuleInfo, Outputs) :-
(
find_list_of_output_args_2(Vars, Modes, Types, ModuleInfo,
OutputsPrime)
->
Outputs = OutputsPrime
;
error("find_list_of_output_args: list length mismatch")
).
:- pred find_list_of_output_args_2(list(prog_var)::in, list(mode)::in,
list(type)::in, module_info::in, list(prog_var)::out) is semidet.
find_list_of_output_args_2([], [], [], _, []).
find_list_of_output_args_2([Var | Vars], [Mode | Modes], [Type | Types],
ModuleInfo, Outputs) :-
find_list_of_output_args_2(Vars, Modes, Types, ModuleInfo, Outputs1),
mode_to_arg_mode(ModuleInfo, Mode, Type, ArgMode),
( ArgMode = top_in ->
Outputs = Outputs1
;
Outputs = [Var | Outputs1]
).
%-----------------------------------------------------------------------------%
:- type apply_tail_recursion_info
---> apply_tail_recursion_info(
moduleinfo :: module_info,
scc_ppids :: assoc_list(pred_proc_id),
detism :: determinism,
outputs :: list(prog_var)
).
:- pred apply_tail_recursion_to_goal(hlds_goal::in,
apply_tail_recursion_info::in, hlds_goal::out, bool::in, bool::out,
maybe(list(prog_var))::out) is det.
apply_tail_recursion_to_goal(Goal0, ApplyInfo, Goal,
FoundTailCall0, FoundTailCall, Continue) :-
Goal0 = GoalExpr0 - GoalInfo0,
(
GoalExpr0 = foreign_proc(_, _, _, _, _, _, _),
Goal = Goal0,
FoundTailCall = FoundTailCall0,
Continue = no
;
GoalExpr0 = call(PredId, ProcId, Args,
Builtin, UnifyContext, SymName),
(
PredProcId = proc(PredId, ProcId),
assoc_list__search(ApplyInfo ^ scc_ppids, PredProcId,
ClonePredProcId),
module_info_pred_proc_info(ApplyInfo ^ moduleinfo,
PredId, ProcId, PredInfo, ProcInfo),
proc_info_interface_determinism(ProcInfo, CallDetism),
CallDetism = ApplyInfo ^ detism,
pred_info_arg_types(PredInfo, Types),
proc_info_argmodes(ProcInfo, Modes),
find_list_of_output_args(Args, Modes, Types,
ApplyInfo ^ moduleinfo, CallOutputs),
CallOutputs = ApplyInfo ^ outputs,
Builtin = not_builtin
->
ClonePredProcId = proc(ClonePredId, CloneProcId),
GoalExpr = call(ClonePredId, CloneProcId, Args,
Builtin, UnifyContext, SymName),
goal_info_add_feature(GoalInfo0, tailcall, GoalInfo),
Goal = GoalExpr - GoalInfo,
FoundTailCall = yes
;
Goal = Goal0,
FoundTailCall = FoundTailCall0
),
Continue = no
;
GoalExpr0 = generic_call(_, _, _, _),
Goal = Goal0,
FoundTailCall = FoundTailCall0,
Continue = no
;
GoalExpr0 = unify(_, _, _, Unify0, _),
Goal = Goal0,
FoundTailCall = FoundTailCall0,
(
Unify0 = assign(ToVar, FromVar)
->
apply_tail_recursion_process_assign(
ApplyInfo ^ outputs, ToVar, FromVar, Outputs),
Continue = yes(Outputs)
;
Continue = no
)
;
GoalExpr0 = conj(Goals0),
apply_tail_recursion_to_conj(Goals0, ApplyInfo,
Goals, FoundTailCall0, FoundTailCall, Continue),
GoalExpr = conj(Goals),
Goal = GoalExpr - GoalInfo0
;
GoalExpr0 = disj(Goals0),
apply_tail_recursion_to_disj(Goals0, ApplyInfo,
Goals, FoundTailCall0, FoundTailCall),
GoalExpr = disj(Goals),
Goal = GoalExpr - GoalInfo0,
Continue = no
;
GoalExpr0 = switch(Var, CanFail, Cases0),
apply_tail_recursion_to_cases(Cases0, ApplyInfo,
Cases, FoundTailCall0, FoundTailCall),
GoalExpr = switch(Var, CanFail, Cases),
Goal = GoalExpr - GoalInfo0,
Continue = no
;
GoalExpr0 = if_then_else(Vars, Cond, Then0, Else0),
apply_tail_recursion_to_goal(Then0, ApplyInfo,
Then, FoundTailCall0, FoundTailCall1, _),
apply_tail_recursion_to_goal(Else0, ApplyInfo,
Else, FoundTailCall1, FoundTailCall, _),
GoalExpr = if_then_else(Vars, Cond, Then, Else),
Goal = GoalExpr - GoalInfo0,
Continue = no
;
GoalExpr0 = par_conj(_),
Goal = Goal0,
FoundTailCall = FoundTailCall0,
Continue = no
;
GoalExpr0 = some(_, _, _),
Goal = Goal0,
FoundTailCall = FoundTailCall0,
Continue = no
;
GoalExpr0 = not(_),
Goal = Goal0,
FoundTailCall = FoundTailCall0,
Continue = no
;
GoalExpr0 = shorthand(_),
error("shorthand in apply_tail_recursion_to_goal")
).
:- pred apply_tail_recursion_process_assign(list(prog_var)::in,
prog_var::in, prog_var::in, list(prog_var)::out) is det.
apply_tail_recursion_process_assign([], _, _, []).
apply_tail_recursion_process_assign([Output0 | Outputs0], ToVar, FromVar,
[Output | Outputs]) :-
( ToVar = Output0 ->
Output = FromVar
;
Output = Output0
),
apply_tail_recursion_process_assign(Outputs0, ToVar, FromVar, Outputs).
:- pred apply_tail_recursion_to_conj(list(hlds_goal)::in,
apply_tail_recursion_info::in, list(hlds_goal)::out,
bool::in, bool::out, maybe(list(prog_var))::out) is det.
apply_tail_recursion_to_conj([], ApplyInfo, [],
FoundTailCall, FoundTailCall, yes(ApplyInfo ^ outputs)).
apply_tail_recursion_to_conj([Goal0 | Goals0], ApplyInfo0, [Goal | Goals],
FoundTailCall0, FoundTailCall, Continue) :-
apply_tail_recursion_to_conj(Goals0, ApplyInfo0, Goals,
FoundTailCall0, FoundTailCall1, Continue1),
(
Continue1 = yes(Outputs),
apply_tail_recursion_to_goal(Goal0,
ApplyInfo0 ^ outputs := Outputs, Goal,
FoundTailCall1, FoundTailCall, Continue)
;
Continue1 = no,
Goal = Goal0,
FoundTailCall = FoundTailCall1,
Continue = no
).
:- pred apply_tail_recursion_to_disj(list(hlds_goal)::in,
apply_tail_recursion_info::in, list(hlds_goal)::out,
bool::in, bool::out) is det.
apply_tail_recursion_to_disj([], _, [], FoundTailCall, FoundTailCall).
apply_tail_recursion_to_disj([Goal0], ApplyInfo, [Goal],
FoundTailCall0, FoundTailCall) :-
apply_tail_recursion_to_goal(Goal0, ApplyInfo, Goal,
FoundTailCall0, FoundTailCall, _).
apply_tail_recursion_to_disj([Goal0 | Goals0], ApplyInfo, [Goal0 | Goals],
FoundTailCall0, FoundTailCall) :-
Goals0 = [_ | _],
apply_tail_recursion_to_disj(Goals0, ApplyInfo, Goals,
FoundTailCall0, FoundTailCall).
:- pred apply_tail_recursion_to_cases(list(case)::in,
apply_tail_recursion_info::in, list(case)::out,
bool::in, bool::out) is det.
apply_tail_recursion_to_cases([], _,
[], FoundTailCall, FoundTailCall).
apply_tail_recursion_to_cases([case(ConsId, Goal0) | Cases0], ApplyInfo,
[case(ConsId, Goal) | Cases], FoundTailCall0, FoundTailCall) :-
apply_tail_recursion_to_goal(Goal0, ApplyInfo, Goal,
FoundTailCall0, FoundTailCall1, _),
apply_tail_recursion_to_cases(Cases0, ApplyInfo, Cases,
FoundTailCall1, FoundTailCall).
%-----------------------------------------------------------------------------%
:- pred figure_out_rec_call_numbers(hlds_goal, int, int, list(int), list(int)).
:- mode figure_out_rec_call_numbers(in, in, out, in, out) is det.
figure_out_rec_call_numbers(Goal, N0, N, TailCallSites0, TailCallSites) :-
Goal = GoalExpr - GoalInfo,
(
GoalExpr = foreign_proc(Attrs, _, _, _, _, _, _),
( may_call_mercury(Attrs, may_call_mercury) ->
N = N0 + 1
;
N = N0
),
TailCallSites = TailCallSites0
;
GoalExpr = call(_, _, _, BuiltinState, _, _),
goal_info_get_features(GoalInfo, Features),
( BuiltinState \= inline_builtin ->
N = N0 + 1
;
N = N0
),
( set__member(tailcall, Features) ->
TailCallSites = [N0|TailCallSites0]
;
TailCallSites = TailCallSites0
)
;
GoalExpr = generic_call(_, _, _, _),
N = N0 + 1,
TailCallSites = TailCallSites0
;
GoalExpr = unify(_, _, _, _, _),
N = N0,
TailCallSites = TailCallSites0
;
GoalExpr = conj(Goals),
figure_out_rec_call_numbers_in_goal_list(Goals, N0, N,
TailCallSites0, TailCallSites)
;
GoalExpr = disj(Goals),
figure_out_rec_call_numbers_in_goal_list(Goals, N0, N,
TailCallSites0, TailCallSites)
;
GoalExpr = switch(_, _, Cases),
figure_out_rec_call_numbers_in_case_list(Cases, N0, N,
TailCallSites0, TailCallSites)
;
GoalExpr = if_then_else(_, Cond, Then, Else),
figure_out_rec_call_numbers(Cond, N0, N1,
TailCallSites0, TailCallSites1),
figure_out_rec_call_numbers(Then, N1, N2,
TailCallSites1, TailCallSites2),
figure_out_rec_call_numbers(Else, N2, N,
TailCallSites2, TailCallSites)
;
GoalExpr = par_conj(Goals),
figure_out_rec_call_numbers_in_goal_list(Goals, N0, N,
TailCallSites0, TailCallSites)
;
GoalExpr = some(_, _, Goal1),
figure_out_rec_call_numbers(Goal1, N0, N,
TailCallSites0, TailCallSites)
;
GoalExpr = not(Goal1),
figure_out_rec_call_numbers(Goal1, N0, N,
TailCallSites0, TailCallSites)
;
GoalExpr = shorthand(_),
error("shorthand in apply_tail_recursion_to_goal")
).
:- pred figure_out_rec_call_numbers_in_goal_list(list(hlds_goal), int, int,
list(int), list(int)).
:- mode figure_out_rec_call_numbers_in_goal_list(in, in, out, in, out) is det.
figure_out_rec_call_numbers_in_goal_list([], N, N,
TailCallSites, TailCallSites).
figure_out_rec_call_numbers_in_goal_list([Goal|Goals], N0, N,
TailCallSites0, TailCallSites) :-
figure_out_rec_call_numbers(Goal, N0, N1,
TailCallSites0, TailCallSites1),
figure_out_rec_call_numbers_in_goal_list(Goals, N1, N,
TailCallSites1, TailCallSites).
:- pred figure_out_rec_call_numbers_in_case_list(list(case), int, int,
list(int), list(int)).
:- mode figure_out_rec_call_numbers_in_case_list(in, in, out, in, out) is det.
figure_out_rec_call_numbers_in_case_list([], N, N,
TailCallSites, TailCallSites).
figure_out_rec_call_numbers_in_case_list([Case|Cases], N0, N,
TailCallSites0, TailCallSites) :-
Case = case(_, Goal),
figure_out_rec_call_numbers(Goal, N0, N1,
TailCallSites0, TailCallSites1),
figure_out_rec_call_numbers_in_case_list(Cases, N1, N,
TailCallSites1, TailCallSites).
%-----------------------------------------------------------------------------%
:- pred transform_predicate(module_info::in, pred_id::in,
pred_table::in, pred_table::out,
list(maybe(layout_data))::in, list(maybe(layout_data))::out) is det.
transform_predicate(ModuleInfo, PredId, PredMap0, PredMap,
ProcStatics0, ProcStatics) :-
map__lookup(PredMap0, PredId, PredInfo0),
ProcIds = pred_info_non_imported_procids(PredInfo0),
pred_info_procedures(PredInfo0, ProcTable0),
list__foldl2(maybe_transform_procedure(ModuleInfo, PredId),
ProcIds, ProcTable0, ProcTable, ProcStatics0, ProcStatics),
pred_info_set_procedures(ProcTable, PredInfo0, PredInfo),
map__det_update(PredMap0, PredId, PredInfo, PredMap).
:- pred maybe_transform_procedure(module_info::in, pred_id::in, proc_id::in,
proc_table::in, proc_table::out,
list(maybe(layout_data))::in, list(maybe(layout_data))::out) is det.
maybe_transform_procedure(ModuleInfo, PredId, ProcId, ProcTable0, ProcTable,
ProcStatics0, ProcStatics) :-
map__lookup(ProcTable0, ProcId, ProcInfo0),
proc_info_goal(ProcInfo0, Goal0),
predicate_module(ModuleInfo, PredId, PredModuleName),
(
% XXX We need to eliminate nondet C code...
Goal0 = foreign_proc(_,_,_,_,_,_, Impl) - _,
Impl = nondet(_, _, _, _, _, _, _, _, _)
->
error("deep profiling is incompatible with nondet foreign code")
;
% We don't want to transform the procedures for
% managing the deep profiling call graph, or we'd get
% infinite recursion.
mercury_profiling_builtin_module(PredModuleName)
->
ProcTable = ProcTable0,
ProcStatics = ProcStatics0
;
transform_procedure2(ModuleInfo, proc(PredId, ProcId),
ProcInfo0, ProcInfo, ProcStatics0, ProcStatics),
map__det_update(ProcTable0, ProcId, ProcInfo, ProcTable)
).
:- pred transform_procedure2(module_info::in, pred_proc_id::in,
proc_info::in, proc_info::out,
list(maybe(layout_data))::in, list(maybe(layout_data))::out) is det.
transform_procedure2(ModuleInfo, PredProcId, Proc0, Proc,
ProcStaticList0, ProcStaticList) :-
proc_info_get_maybe_deep_profile_info(Proc0, MaybeRecInfo),
proc_info_interface_code_model(Proc0, CodeModel),
(
CodeModel = model_det,
(
MaybeRecInfo = yes(RecInfo),
RecInfo ^ role = inner_proc(_)
->
transform_inner_proc(ModuleInfo, PredProcId, Proc0,
Proc, MaybeProcStatic)
;
transform_det_proc(ModuleInfo, PredProcId, Proc0,
Proc, MaybeProcStatic)
)
;
CodeModel = model_semi,
(
MaybeRecInfo = yes(RecInfo),
RecInfo ^ role = inner_proc(_)
->
transform_inner_proc(ModuleInfo, PredProcId, Proc0,
Proc, MaybeProcStatic)
;
transform_semi_proc(ModuleInfo, PredProcId, Proc0,
Proc, MaybeProcStatic)
)
;
CodeModel = model_non,
transform_non_proc(ModuleInfo, PredProcId, Proc0,
Proc, MaybeProcStatic)
),
ProcStaticList = [MaybeProcStatic | ProcStaticList0].
%-----------------------------------------------------------------------------%
:- type deep_info --->
deep_info(
module_info :: module_info,
pred_proc_id :: pred_proc_id,
current_csd :: prog_var,
site_num_counter :: counter,
call_sites :: list(call_site_static_data),
vars :: prog_varset,
var_types :: vartypes,
proc_filename :: string,
maybe_rec_info :: maybe(deep_profile_proc_info)
).
:- pred transform_det_proc(module_info::in, pred_proc_id::in,
proc_info::in, proc_info::out, maybe(layout_data)::out) is det.
transform_det_proc(ModuleInfo, PredProcId, !Proc, yes(ProcStatic)) :-
proc_info_goal(!.Proc, Goal0),
Goal0 = _ - GoalInfo0,
proc_info_varset(!.Proc, Vars0),
proc_info_vartypes(!.Proc, VarTypes0),
CPointerType = c_pointer_type,
varset__new_named_var(Vars0, "TopCSD", TopCSD, Vars1),
map__set(VarTypes0, TopCSD, CPointerType, VarTypes1),
varset__new_named_var(Vars1, "MiddleCSD", MiddleCSD, Vars2),
map__set(VarTypes1, MiddleCSD, CPointerType, VarTypes2),
varset__new_named_var(Vars2, "ProcStatic", ProcStaticVar, Vars3),
map__set(VarTypes2, ProcStaticVar, CPointerType, VarTypes3),
module_info_globals(ModuleInfo, Globals),
globals__lookup_bool_option(Globals, use_activation_counts,
UseActivationCounts),
(
UseActivationCounts = no,
varset__new_named_var(Vars3, "ActivationPtr", ActivationPtr0,
Vars5),
map__set(VarTypes3, ActivationPtr0, CPointerType, VarTypes5),
MaybeActivationPtr = yes(ActivationPtr0)
;
UseActivationCounts = yes,
Vars5 = Vars3,
VarTypes5 = VarTypes3,
MaybeActivationPtr = no
),
proc_info_context(!.Proc, Context),
FileName = term__context_file(Context),
LineNumber = term__context_line(Context),
proc_info_get_maybe_deep_profile_info(!.Proc, MaybeRecInfo),
DeepInfo0 = deep_info(ModuleInfo, PredProcId, MiddleCSD,
counter__init(0), [], Vars5, VarTypes5,
FileName, MaybeRecInfo),
transform_goal([], Goal0, TransformedGoal, _, DeepInfo0, DeepInfo),
Vars = DeepInfo ^ vars,
VarTypes = DeepInfo ^ var_types,
CallSites = DeepInfo ^ call_sites,
(
MaybeRecInfo = yes(RecInfo),
RecInfo ^ role = inner_proc(OuterPredProcId)
->
OuterPredProcId = proc(PredId, ProcId)
;
PredProcId = proc(PredId, ProcId)
),
RttiProcLabel = rtti__make_rtti_proc_label(ModuleInfo, PredId, ProcId),
IsInInterface = is_proc_in_interface(ModuleInfo, PredId, ProcId),
ProcStatic = proc_static_data(RttiProcLabel, FileName, LineNumber,
IsInInterface, CallSites),
ProcStaticConsId = deep_profiling_proc_static(RttiProcLabel),
generate_unify(ProcStaticConsId, ProcStaticVar, BindProcStaticVarGoal),
(
MaybeActivationPtr = yes(ActivationPtr1),
generate_call(ModuleInfo, "det_call_port_code_sr", 4,
[ProcStaticVar, TopCSD, MiddleCSD, ActivationPtr1],
[TopCSD, MiddleCSD, ActivationPtr1], CallPortCode),
generate_call(ModuleInfo, "det_exit_port_code_sr", 3,
[TopCSD, MiddleCSD, ActivationPtr1], [], ExitPortCode)
;
MaybeActivationPtr = no,
generate_call(ModuleInfo, "det_call_port_code_ac", 3,
[ProcStaticVar, TopCSD, MiddleCSD],
[TopCSD, MiddleCSD], CallPortCode),
generate_call(ModuleInfo, "det_exit_port_code_ac", 2,
[TopCSD, MiddleCSD], [], ExitPortCode)
),
goal_info_add_feature(GoalInfo0, impure, GoalInfo),
Goal = conj([
BindProcStaticVarGoal,
CallPortCode,
TransformedGoal,
ExitPortCode
]) - GoalInfo,
proc_info_set_varset(Vars, !Proc),
proc_info_set_vartypes(VarTypes, !Proc),
proc_info_set_goal(Goal, !Proc).
:- pred transform_semi_proc(module_info::in, pred_proc_id::in,
proc_info::in, proc_info::out, maybe(layout_data)::out) is det.
transform_semi_proc(ModuleInfo, PredProcId, !Proc, yes(ProcStatic)) :-
proc_info_goal(!.Proc, Goal0),
Goal0 = _ - GoalInfo0,
proc_info_varset(!.Proc, Vars0),
proc_info_vartypes(!.Proc, VarTypes0),
CPointerType = c_pointer_type,
varset__new_named_var(Vars0, "TopCSD", TopCSD, Vars1),
map__set(VarTypes0, TopCSD, CPointerType, VarTypes1),
varset__new_named_var(Vars1, "MiddleCSD", MiddleCSD, Vars2),
map__set(VarTypes1, MiddleCSD, CPointerType, VarTypes2),
varset__new_named_var(Vars2, "ProcStatic", ProcStaticVar, Vars3),
map__set(VarTypes2, ProcStaticVar, CPointerType, VarTypes3),
module_info_globals(ModuleInfo, Globals),
globals__lookup_bool_option(Globals, use_activation_counts,
UseActivationCounts),
(
UseActivationCounts = no,
varset__new_named_var(Vars3, "ActivationPtr", ActivationPtr0,
Vars5),
map__set(VarTypes3, ActivationPtr0, CPointerType, VarTypes5),
MaybeActivationPtr = yes(ActivationPtr0)
;
UseActivationCounts = yes,
Vars5 = Vars3,
VarTypes5 = VarTypes3,
MaybeActivationPtr = no
),
proc_info_context(!.Proc, Context),
FileName = term__context_file(Context),
LineNumber = term__context_line(Context),
proc_info_get_maybe_deep_profile_info(!.Proc, MaybeRecInfo),
DeepInfo0 = deep_info(ModuleInfo, PredProcId, MiddleCSD,
counter__init(0), [], Vars5, VarTypes5,
FileName, MaybeRecInfo),
transform_goal([], Goal0, TransformedGoal, _, DeepInfo0, DeepInfo),
Vars = DeepInfo ^ vars,
VarTypes = DeepInfo ^ var_types,
CallSites = DeepInfo ^ call_sites,
(
MaybeRecInfo = yes(RecInfo),
RecInfo ^ role = inner_proc(OuterPredProcId)
->
OuterPredProcId = proc(PredId, ProcId)
;
PredProcId = proc(PredId, ProcId)
),
RttiProcLabel = rtti__make_rtti_proc_label(ModuleInfo, PredId, ProcId),
IsInInterface = is_proc_in_interface(ModuleInfo, PredId, ProcId),
ProcStatic = proc_static_data(RttiProcLabel, FileName, LineNumber,
IsInInterface, CallSites),
ProcStaticConsId = deep_profiling_proc_static(RttiProcLabel),
generate_unify(ProcStaticConsId, ProcStaticVar, BindProcStaticVarGoal),
(
MaybeActivationPtr = yes(ActivationPtr1),
generate_call(ModuleInfo, "semi_call_port_code_sr", 4,
[ProcStaticVar, TopCSD, MiddleCSD, ActivationPtr1],
[TopCSD, MiddleCSD, ActivationPtr1], CallPortCode),
generate_call(ModuleInfo, "semi_exit_port_code_sr", 3,
[TopCSD, MiddleCSD, ActivationPtr1], [], ExitPortCode),
generate_call(ModuleInfo, "semi_fail_port_code_sr", 3,
[TopCSD, MiddleCSD, ActivationPtr1], no, failure,
FailPortCode),
NewNonlocals = list_to_set([TopCSD, MiddleCSD, ActivationPtr1])
;
MaybeActivationPtr = no,
generate_call(ModuleInfo, "semi_call_port_code_ac", 3,
[ProcStaticVar, TopCSD, MiddleCSD],
[TopCSD, MiddleCSD], CallPortCode),
generate_call(ModuleInfo, "semi_exit_port_code_ac", 2,
[TopCSD, MiddleCSD], [], ExitPortCode),
generate_call(ModuleInfo, "semi_fail_port_code_ac", 2,
[TopCSD, MiddleCSD], no, failure, FailPortCode),
NewNonlocals = list_to_set([TopCSD, MiddleCSD])
),
ExitConjGoalInfo = goal_info_add_nonlocals_make_impure(GoalInfo0,
NewNonlocals),
goal_info_add_feature(GoalInfo0, impure, GoalInfo),
Goal = conj([
BindProcStaticVarGoal,
CallPortCode,
disj([
conj([
TransformedGoal,
ExitPortCode
]) - ExitConjGoalInfo,
FailPortCode
]) - ExitConjGoalInfo
]) - GoalInfo,
proc_info_set_varset(Vars, !Proc),
proc_info_set_vartypes(VarTypes, !Proc),
proc_info_set_goal(Goal, !Proc).
:- pred transform_non_proc(module_info::in, pred_proc_id::in,
proc_info::in, proc_info::out, maybe(layout_data)::out) is det.
transform_non_proc(ModuleInfo, PredProcId, !Proc, yes(ProcStatic)) :-
proc_info_goal(!.Proc, Goal0),
Goal0 = _ - GoalInfo0,
proc_info_varset(!.Proc, Vars0),
proc_info_vartypes(!.Proc, VarTypes0),
CPointerType = c_pointer_type,
varset__new_named_var(Vars0, "TopCSD", TopCSD, Vars1),
map__set(VarTypes0, TopCSD, CPointerType, VarTypes1),
varset__new_named_var(Vars1, "MiddleCSD", MiddleCSD, Vars2),
map__set(VarTypes1, MiddleCSD, CPointerType, VarTypes2),
varset__new_named_var(Vars2, "ProcStatic", ProcStaticVar, Vars3),
map__set(VarTypes2, ProcStaticVar, CPointerType, VarTypes3),
module_info_globals(ModuleInfo, Globals),
globals__lookup_bool_option(Globals, use_activation_counts,
UseActivationCounts),
(
UseActivationCounts = no,
varset__new_named_var(Vars3, "OldOutermost",
OldOutermostProcDyn0, Vars4),
map__set(VarTypes3, OldOutermostProcDyn0, CPointerType,
VarTypes4),
varset__new_named_var(Vars4, "NewOutermost",
NewOutermostProcDyn, Vars5),
map__set(VarTypes4, NewOutermostProcDyn, CPointerType,
VarTypes5),
MaybeOldActivationPtr = yes(OldOutermostProcDyn0)
;
UseActivationCounts = yes,
varset__new_named_var(Vars3, "NewOutermost",
NewOutermostProcDyn, Vars5),
map__set(VarTypes3, NewOutermostProcDyn, CPointerType,
VarTypes5),
MaybeOldActivationPtr = no
),
proc_info_context(!.Proc, Context),
FileName = term__context_file(Context),
LineNumber = term__context_line(Context),
proc_info_get_maybe_deep_profile_info(!.Proc, MaybeRecInfo),
DeepInfo0 = deep_info(ModuleInfo, PredProcId, MiddleCSD,
counter__init(0), [], Vars5, VarTypes5,
FileName, MaybeRecInfo),
transform_goal([], Goal0, TransformedGoal, _, DeepInfo0, DeepInfo),
Vars = DeepInfo ^ vars,
VarTypes = DeepInfo ^ var_types,
CallSites = DeepInfo ^ call_sites,
PredProcId = proc(PredId, ProcId),
RttiProcLabel = rtti__make_rtti_proc_label(ModuleInfo, PredId, ProcId),
IsInInterface = is_proc_in_interface(ModuleInfo, PredId, ProcId),
ProcStatic = proc_static_data(RttiProcLabel, FileName, LineNumber,
IsInInterface, CallSites),
ProcStaticConsId = deep_profiling_proc_static(RttiProcLabel),
generate_unify(ProcStaticConsId, ProcStaticVar, BindProcStaticVarGoal),
(
MaybeOldActivationPtr = yes(OldOutermostProcDyn2),
generate_call(ModuleInfo, "non_call_port_code_sr", 5,
[ProcStaticVar, TopCSD, MiddleCSD,
OldOutermostProcDyn2, NewOutermostProcDyn],
[TopCSD, MiddleCSD,
OldOutermostProcDyn2, NewOutermostProcDyn],
CallPortCode),
generate_call(ModuleInfo, "non_exit_port_code_sr", 3,
[TopCSD, MiddleCSD, OldOutermostProcDyn2], [],
ExitPortCode),
generate_call(ModuleInfo, "non_fail_port_code_sr", 3,
[TopCSD, MiddleCSD, OldOutermostProcDyn2], no,
failure, FailPortCode),
generate_call(ModuleInfo, "non_redo_port_code_sr", 2,
[MiddleCSD, NewOutermostProcDyn], no,
failure, RedoPortCode0),
NewNonlocals = list_to_set(
[TopCSD, MiddleCSD, OldOutermostProcDyn2])
;
MaybeOldActivationPtr = no,
generate_call(ModuleInfo, "non_call_port_code_ac", 4,
[ProcStaticVar, TopCSD, MiddleCSD, NewOutermostProcDyn],
[TopCSD, MiddleCSD, NewOutermostProcDyn],
CallPortCode),
generate_call(ModuleInfo, "non_exit_port_code_ac", 2,
[TopCSD, MiddleCSD], [], ExitPortCode),
generate_call(ModuleInfo, "non_fail_port_code_ac", 2,
[TopCSD, MiddleCSD], no, failure, FailPortCode),
generate_call(ModuleInfo, "non_redo_port_code_ac", 2,
[MiddleCSD, NewOutermostProcDyn], no,
failure, RedoPortCode0),
NewNonlocals = list_to_set([TopCSD, MiddleCSD])
),
RedoPortCode0 = RedoPortExpr - RedoPortGoalInfo0,
goal_info_add_feature(RedoPortGoalInfo0,
preserve_backtrack_into, RedoPortGoalInfo),
RedoPortCode = 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.
goal_info_get_determinism(GoalInfo0, Detism0),
determinism_components(Detism0, CanFail, _),
determinism_components(Detism, CanFail, at_most_many),
goal_info_set_determinism(GoalInfo0, Detism, GoalInfo1),
ExitRedoNonLocals = set__union(NewNonlocals,
list_to_set([NewOutermostProcDyn])),
ExitRedoGoalInfo = impure_reachable_init_goal_info(ExitRedoNonLocals,
multidet),
CallExitRedoGoalInfo = goal_info_add_nonlocals_make_impure(GoalInfo1,
ExitRedoNonLocals),
goal_info_add_feature(GoalInfo1, impure, GoalInfo),
Goal = conj([
BindProcStaticVarGoal,
CallPortCode,
disj([
conj([
TransformedGoal,
disj([
ExitPortCode,
RedoPortCode
]) - ExitRedoGoalInfo
]) - CallExitRedoGoalInfo,
FailPortCode
]) - CallExitRedoGoalInfo
]) - GoalInfo,
proc_info_set_varset(Vars, !Proc),
proc_info_set_vartypes(VarTypes, !Proc),
proc_info_set_goal(Goal, !Proc).
:- pred transform_inner_proc(module_info::in, pred_proc_id::in,
proc_info::in, proc_info::out, maybe(layout_data)::out) is det.
transform_inner_proc(ModuleInfo, PredProcId, !Proc, no) :-
proc_info_goal(!.Proc, Goal0),
Goal0 = _ - GoalInfo0,
proc_info_varset(!.Proc, Vars0),
proc_info_vartypes(!.Proc, VarTypes0),
CPointerType = c_pointer_type,
% MiddleCSD should be unused
varset__new_named_var(Vars0, "MiddleCSD", MiddleCSD, Vars1),
map__set(VarTypes0, MiddleCSD, CPointerType, VarTypes1),
goal_info_get_context(GoalInfo0, Context),
FileName = term__context_file(Context),
proc_info_get_maybe_deep_profile_info(!.Proc, MaybeRecInfo),
DeepInfo0 = deep_info(ModuleInfo, PredProcId, MiddleCSD,
counter__init(0), [], Vars1, VarTypes1,
FileName, MaybeRecInfo),
transform_goal([], Goal0, TransformedGoal, _, DeepInfo0, DeepInfo),
Vars = DeepInfo ^ vars,
VarTypes = DeepInfo ^ var_types,
proc_info_set_varset(Vars, !Proc),
proc_info_set_vartypes(VarTypes, !Proc),
proc_info_set_goal(TransformedGoal, !Proc).
%-----------------------------------------------------------------------------%
:- 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),
(
( pred_info_is_exported(PredInfo)
; pred_info_is_pseudo_exported(PredInfo)
)
->
IsInInterface = yes
;
IsInInterface = no
).
%-----------------------------------------------------------------------------%
:- pred add_impurity_if_needed(bool::in, hlds_goal_info::in,
hlds_goal_info::out) is det.
add_impurity_if_needed(AddedImpurity, GoalInfo0, GoalInfo) :-
(
AddedImpurity = no,
GoalInfo = GoalInfo0
;
AddedImpurity = yes,
goal_info_add_feature(GoalInfo0, impure, GoalInfo)
).
%-----------------------------------------------------------------------------%
:- pred transform_goal(goal_path::in, hlds_goal::in, hlds_goal::out, bool::out,
deep_info::in, deep_info::out) is det.
transform_goal(Path, conj(Goals0) - Info0, conj(Goals) - Info,
AddedImpurity) -->
transform_conj(0, Path, Goals0, Goals, AddedImpurity),
{ add_impurity_if_needed(AddedImpurity, Info0, Info) }.
transform_goal(Path, par_conj(Goals0) - Info0,
par_conj(Goals) - Info, AddedImpurity) -->
transform_conj(0, Path, Goals0, Goals, AddedImpurity),
{ add_impurity_if_needed(AddedImpurity, Info0, Info) }.
transform_goal(Path, switch(Var, CF, Cases0) - Info0,
switch(Var, CF, Cases) - Info, AddedImpurity) -->
transform_switch(list__length(Cases0), 0, Path, Cases0, Cases,
AddedImpurity),
{ add_impurity_if_needed(AddedImpurity, Info0, Info) }.
transform_goal(Path, disj(Goals0) - Info0, disj(Goals) - Info,
AddedImpurity) -->
transform_disj(0, Path, Goals0, Goals, AddedImpurity),
{ add_impurity_if_needed(AddedImpurity, Info0, Info) }.
transform_goal(Path, not(Goal0) - Info0, not(Goal) - Info, AddedImpurity) -->
transform_goal([neg | Path], Goal0, Goal, AddedImpurity),
{ add_impurity_if_needed(AddedImpurity, Info0, Info) }.
transform_goal(Path, some(QVars, CanRemove, Goal0) - Info0,
some(QVars, CanRemove, Goal) - Info, AddedImpurity) -->
{ Goal0 = _ - InnerInfo },
{ goal_info_get_determinism(Info0, OuterDetism) },
{ goal_info_get_determinism(InnerInfo, InnerDetism) },
{ InnerDetism = OuterDetism ->
Info1 = Info0,
MaybeCut = no_cut
;
% Given a subgoal containing both nondet code and impure code,
% determinism analysis will remove the `some' wrapped around
% that subgoal if it is allowed to. If we get here, then the
% subgoal inside the `some' contains nondet code, and the deep
% profiling transformation will make it impure as well.
goal_info_add_feature(Info0, keep_this_commit, Info1),
MaybeCut = cut
},
transform_goal([exist(MaybeCut) | Path], Goal0, Goal, AddedImpurity),
{ add_impurity_if_needed(AddedImpurity, Info1, Info) }.
transform_goal(Path, if_then_else(IVars, Cond0, Then0, Else0) - Info0,
if_then_else(IVars, Cond, Then, Else) - Info,
AddedImpurity) -->
transform_goal([ite_cond | Path], Cond0, Cond, AddedImpurityC),
transform_goal([ite_then | Path], Then0, Then, AddedImpurityT),
transform_goal([ite_else | Path], Else0, Else, AddedImpurityE),
{
( AddedImpurityC = yes
; AddedImpurityT = yes
; AddedImpurityE = yes
)
->
AddedImpurity = yes
;
AddedImpurity = no
},
{ add_impurity_if_needed(AddedImpurity, Info0, Info) }.
transform_goal(_, shorthand(_) - _, _, _) -->
{ error("transform_goal/6: shorthand should have gone by now") }.
transform_goal(Path, Goal0 - Info0, GoalAndInfo, AddedImpurity) -->
{ Goal0 = foreign_proc(Attrs, _, _, _, _, _, _) },
( { may_call_mercury(Attrs, may_call_mercury) } ->
wrap_foreign_code(Path, Goal0 - Info0, GoalAndInfo),
{ AddedImpurity = yes }
;
{ GoalAndInfo = Goal0 - Info0 },
{ AddedImpurity = no }
).
transform_goal(_Path, Goal - Info, Goal - Info, no) -->
{ Goal = unify(_, _, _, _, _) }.
transform_goal(Path, Goal0 - Info0, GoalAndInfo, yes) -->
{ Goal0 = call(_, _, _, BuiltinState, _, _) },
( { BuiltinState \= inline_builtin } ->
wrap_call(Path, Goal0 - Info0, GoalAndInfo)
;
{ GoalAndInfo = Goal0 - Info0 }
).
transform_goal(Path, Goal0 - Info0, GoalAndInfo, AddedImpurity) -->
{ Goal0 = generic_call(GenericCall, _, _, _) },
(
{ GenericCall = higher_order(_, _, _, _) },
wrap_call(Path, Goal0 - Info0, GoalAndInfo),
{ AddedImpurity = yes }
;
{ GenericCall = class_method(_, _, _, _) },
wrap_call(Path, Goal0 - Info0, GoalAndInfo),
{ AddedImpurity = yes }
;
{ GenericCall = unsafe_cast },
{ GoalAndInfo = Goal0 - Info0 },
{ AddedImpurity = no }
;
{ GenericCall = aditi_builtin(_, _) },
{ error("deep_profiling__transform_call: aditi_builtin") }
).
:- pred transform_conj(int::in, goal_path::in,
list(hlds_goal)::in, list(hlds_goal)::out, bool::out,
deep_info::in, deep_info::out) is det.
transform_conj(_, _, [], [], no) --> [].
transform_conj(N, Path, [Goal0 | Goals0], [Goal | Goals], AddedImpurity) -->
{ N1 = N + 1 },
transform_goal([conj(N1) | Path], Goal0, Goal, AddedImpurityFirst),
transform_conj(N1, Path, Goals0, Goals, AddedImpurityLater),
{ bool__or(AddedImpurityFirst, AddedImpurityLater, AddedImpurity) }.
:- pred transform_disj(int::in, goal_path::in,
list(hlds_goal)::in, list(hlds_goal)::out, bool::out,
deep_info::in, deep_info::out) is det.
transform_disj(_, _, [], [], no) --> [].
transform_disj(N, Path, [Goal0 | Goals0], [Goal | Goals], AddedImpurity) -->
{ N1 = N + 1 },
transform_goal([disj(N1) | Path], Goal0, Goal, AddedImpurityFirst),
transform_disj(N1, Path, Goals0, Goals, AddedImpurityLater),
{ bool__or(AddedImpurityFirst, AddedImpurityLater, AddedImpurity) }.
:- pred transform_switch(int::in, int::in, goal_path::in,
list(case)::in, list(case)::out, bool::out,
deep_info::in, deep_info::out) is det.
transform_switch(_, _, _, [], [], no) --> [].
transform_switch(NumCases, N, Path, [case(Id, Goal0) | Goals0],
[case(Id, Goal) | Goals], AddedImpurity) -->
{ N1 = N + 1 },
transform_goal([switch(NumCases, N1) | Path], Goal0, Goal,
AddedImpurityFirst),
transform_switch(NumCases, N1, Path, Goals0, Goals,
AddedImpurityLater),
{ bool__or(AddedImpurityFirst, AddedImpurityLater, AddedImpurity) }.
:- pred wrap_call(goal_path::in, hlds_goal::in, hlds_goal::out,
deep_info::in, deep_info::out) is det.
wrap_call(GoalPath, Goal0, Goal, DeepInfo0, DeepInfo) :-
Goal0 = GoalExpr - GoalInfo0,
ModuleInfo = DeepInfo0 ^ module_info,
goal_info_get_features(GoalInfo0, GoalFeatures),
goal_info_remove_feature(GoalInfo0, tailcall, GoalInfo1),
goal_info_add_feature(GoalInfo1, impure, GoalInfo),
% 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 = GoalExpr - GoalInfo,
SiteNumCounter0 = DeepInfo0 ^ site_num_counter,
counter__allocate(SiteNum, SiteNumCounter0, SiteNumCounter),
varset__new_named_var(DeepInfo0 ^ vars, "SiteNum", SiteNumVar, Vars1),
IntType = int_type,
map__set(DeepInfo0 ^ var_types, SiteNumVar, IntType, VarTypes1),
generate_unify(int_const(SiteNum), SiteNumVar, SiteNumVarGoal),
DeepInfo1 = (((DeepInfo0 ^ vars := Vars1)
^ var_types := VarTypes1)
^ site_num_counter := SiteNumCounter),
goal_info_get_context(GoalInfo0, Context),
FileName0 = term__context_file(Context),
LineNumber = term__context_line(Context),
compress_filename(DeepInfo1, FileName0, FileName),
classify_call(ModuleInfo, GoalExpr, CallKind),
(
CallKind = normal(PredProcId),
( set__member(tailcall, GoalFeatures) ->
generate_call(ModuleInfo, "prepare_for_tail_call", 1,
[SiteNumVar], [], PrepareGoal)
;
generate_call(ModuleInfo, "prepare_for_normal_call", 1,
[SiteNumVar], [], PrepareGoal)
),
PredProcId = proc(PredId, ProcId),
TypeSubst = compute_type_subst(GoalExpr, DeepInfo1),
MaybeRecInfo = DeepInfo1 ^ maybe_rec_info,
(
MaybeRecInfo = yes(RecInfo1),
RecInfo1 ^ role = inner_proc(OuterPredProcId),
PredProcId = DeepInfo1 ^ pred_proc_id
->
OuterPredProcId = proc(OuterPredId, OuterProcId),
RttiProcLabel = rtti__make_rtti_proc_label(ModuleInfo,
OuterPredId, OuterProcId)
;
MaybeRecInfo = yes(RecInfo2),
RecInfo2 ^ role = outer_proc(InnerPredProcId),
PredProcId = InnerPredProcId
->
OuterPredProcId = DeepInfo1 ^ pred_proc_id,
OuterPredProcId = proc(OuterPredId, OuterProcId),
RttiProcLabel = rtti__make_rtti_proc_label(ModuleInfo,
OuterPredId, OuterProcId)
;
RttiProcLabel = rtti__make_rtti_proc_label(ModuleInfo,
PredId, ProcId)
),
CallSite = normal_call(RttiProcLabel, TypeSubst,
FileName, LineNumber, GoalPath),
Goal2 = Goal1,
DeepInfo3 = DeepInfo1
;
CallKind = special(_PredProcId, TypeInfoVar),
generate_call(ModuleInfo, "prepare_for_special_call", 2,
[SiteNumVar, TypeInfoVar], [], PrepareGoal),
CallSite = special_call(FileName, LineNumber, GoalPath),
Goal2 = Goal1,
DeepInfo3 = DeepInfo1
;
CallKind = generic(Generic),
(
Generic = higher_order(ClosureVar, _, _, _),
generate_call(ModuleInfo, "prepare_for_ho_call", 2,
[SiteNumVar, ClosureVar], [], PrepareGoal),
CallSite = higher_order_call(FileName, LineNumber,
GoalPath),
DeepInfo2 = DeepInfo1
;
Generic = class_method(TypeClassInfoVar, MethodNum,
_, _),
varset__new_named_var(DeepInfo1 ^ vars, "MethodNum",
MethodNumVar, Vars2),
map__set(DeepInfo1 ^ var_types, MethodNumVar, IntType,
VarTypes2),
generate_unify(int_const(MethodNum), MethodNumVar,
MethodNumVarGoal),
DeepInfo2 = ((DeepInfo1 ^ vars := Vars2)
^ var_types := VarTypes2),
generate_call(ModuleInfo, "prepare_for_method_call", 3,
[SiteNumVar, TypeClassInfoVar, MethodNumVar],
[], PrepareCallGoal),
PrepareCallGoal = _ - PrepareCallGoalInfo,
PrepareGoal = conj([
MethodNumVarGoal,
PrepareCallGoal
]) - PrepareCallGoalInfo,
CallSite = method_call(FileName, LineNumber, GoalPath)
;
Generic = unsafe_cast,
error("deep_profiling__wrap_call: unsafe_cast")
;
Generic = aditi_builtin(_, _),
error("deep_profiling__wrap_call: aditi_builtin")
),
goal_info_get_code_model(GoalInfo0, GoalCodeModel),
module_info_globals(ModuleInfo, Globals),
globals__lookup_bool_option(Globals,
use_zeroing_for_ho_cycles, UseZeroing),
( UseZeroing = yes ->
transform_higher_order_call(Globals, GoalCodeModel,
Goal1, Goal2, DeepInfo2, DeepInfo3)
;
Goal2 = Goal1,
DeepInfo3 = DeepInfo2
)
),
DeepInfo4 = DeepInfo3 ^ call_sites :=
(DeepInfo3 ^ call_sites ++ [CallSite]),
(
set__member(tailcall, GoalFeatures),
DeepInfo4 ^ maybe_rec_info = yes(RecInfo),
RecInfo ^ role = outer_proc(_)
->
VisSCC = RecInfo ^ visible_scc,
MiddleCSD = DeepInfo4 ^ current_csd,
(
VisSCC = [],
CallGoals = [],
ExitGoals = [],
FailGoals = [],
SaveRestoreVars = [],
DeepInfo = DeepInfo4
;
VisSCC = [SCCmember],
generate_recursion_counter_saves_and_restores(
SCCmember ^ rec_call_sites, MiddleCSD,
CallGoals, ExitGoals, FailGoals,
SaveRestoreVars, DeepInfo4, DeepInfo)
;
VisSCC = [_, _ | _],
error("wrap_call: multi-procedure SCCs not yet implemented")
),
goal_info_get_code_model(GoalInfo0, CodeModel),
( CodeModel = model_det ->
list__condense([
CallGoals,
[SiteNumVarGoal, PrepareGoal, Goal2],
ExitGoals
], Goals),
Goal = conj(Goals) - GoalInfo
;
ExtraVars = list_to_set([MiddleCSD | SaveRestoreVars]),
WrappedGoalGoalInfo =
goal_info_add_nonlocals_make_impure(GoalInfo,
ExtraVars),
ReturnFailsGoalInfo =
impure_unreachable_init_goal_info(
ExtraVars, failure),
FailGoalInfo = fail_goal_info,
FailGoal = disj([]) - FailGoalInfo,
list__append(FailGoals, [FailGoal], FailGoalsAndFail),
list__condense([
CallGoals,
[disj([
conj([
SiteNumVarGoal,
PrepareGoal,
Goal2 |
ExitGoals
]) - WrappedGoalGoalInfo,
conj(
FailGoalsAndFail
) - ReturnFailsGoalInfo
]) - WrappedGoalGoalInfo]
], Goals),
Goal = conj(Goals) - GoalInfo
)
;
Goal = conj([
SiteNumVarGoal,
PrepareGoal,
Goal2
]) - GoalInfo,
DeepInfo = DeepInfo4
).
:- pred transform_higher_order_call(globals::in, code_model::in,
hlds_goal::in, hlds_goal::out, deep_info::in, deep_info::out) is det.
transform_higher_order_call(Globals, CodeModel, Goal0, Goal,
DeepInfo0, DeepInfo) :-
Vars0 = DeepInfo0 ^ vars,
VarTypes0 = DeepInfo0 ^ var_types,
CPointerType = c_pointer_type,
varset__new_named_var(Vars0, "SavedPtr", SavedPtrVar, Vars1),
map__set(VarTypes0, SavedPtrVar, CPointerType, VarTypes1),
globals__lookup_bool_option(Globals, use_activation_counts,
UseActivationCounts),
(
UseActivationCounts = yes,
IntType = int_type,
varset__new_named_var(Vars1, "SavedCounter", SavedCountVar,
Vars),
map__set(VarTypes1, SavedCountVar, IntType, VarTypes),
DeepInfo1 = DeepInfo0 ^ vars := Vars,
DeepInfo = DeepInfo1 ^ var_types := VarTypes,
ExtraNonLocals = set__list_to_set(
[SavedCountVar, SavedPtrVar]),
generate_call(DeepInfo ^ module_info,
"save_and_zero_activation_info_ac", 2,
[SavedCountVar, SavedPtrVar],
[SavedCountVar, SavedPtrVar], SaveStuff),
generate_call(DeepInfo ^ module_info,
"reset_activation_info_ac", 2,
[SavedCountVar, SavedPtrVar], [], RestoreStuff),
generate_call(DeepInfo ^ module_info,
"rezero_activation_info_ac", 0,
[], [], ReZeroStuff)
;
UseActivationCounts = no,
DeepInfo1 = DeepInfo0 ^ vars := Vars1,
DeepInfo = DeepInfo1 ^ var_types := VarTypes1,
ExtraNonLocals = set__list_to_set([SavedPtrVar]),
generate_call(DeepInfo ^ module_info,
"save_and_zero_activation_info_sr", 1,
[SavedPtrVar], [SavedPtrVar], SaveStuff),
generate_call(DeepInfo ^ module_info,
"reset_activation_info_sr", 1,
[SavedPtrVar], [], RestoreStuff),
generate_call(DeepInfo ^ module_info,
"rezero_activation_info_sr", 0,
[], [], ReZeroStuff)
),
Goal0 = _ - GoalInfo0,
ExtGoalInfo = goal_info_add_nonlocals_make_impure(GoalInfo0,
ExtraNonLocals),
% XXX We should build up NoBindExtGoalInfo from scratch.
instmap_delta_init_reachable(EmptyDelta),
goal_info_set_instmap_delta(ExtGoalInfo, EmptyDelta,
NoBindExtGoalInfo),
FailGoalInfo = fail_goal_info,
FailGoal = disj([]) - FailGoalInfo,
RestoreFailGoalInfo = impure_unreachable_init_goal_info(ExtraNonLocals,
failure),
RezeroFailGoalInfo = impure_unreachable_init_goal_info(set__init,
failure),
goal_info_add_feature(GoalInfo0, impure, GoalInfo),
(
CodeModel = model_det,
Goal = conj([
SaveStuff,
Goal0,
RestoreStuff
]) - GoalInfo
;
CodeModel = model_semi,
Goal = conj([
SaveStuff,
disj([
conj([
Goal0,
RestoreStuff
]) - ExtGoalInfo,
conj([
RestoreStuff,
FailGoal
]) - RestoreFailGoalInfo
]) - ExtGoalInfo
]) - GoalInfo
;
CodeModel = model_non,
Goal = conj([
SaveStuff,
disj([
conj([
Goal0,
disj([
RestoreStuff,
conj([
ReZeroStuff,
FailGoal
]) - RezeroFailGoalInfo
]) - NoBindExtGoalInfo
]) - ExtGoalInfo,
conj([
RestoreStuff,
FailGoal
]) - RestoreFailGoalInfo
]) - ExtGoalInfo
]) - GoalInfo
).
:- pred wrap_foreign_code(goal_path::in, hlds_goal::in, hlds_goal::out,
deep_info::in, deep_info::out) is det.
wrap_foreign_code(GoalPath, Goal0, Goal, DeepInfo0, DeepInfo) :-
Goal0 = _ - GoalInfo0,
ModuleInfo = DeepInfo0 ^ module_info,
SiteNumCounter0 = DeepInfo0 ^ site_num_counter,
counter__allocate(SiteNum, SiteNumCounter0, SiteNumCounter),
varset__new_named_var(DeepInfo0 ^ vars, "SiteNum", SiteNumVar, Vars),
map__set(DeepInfo0 ^ var_types, SiteNumVar, int_type, VarTypes),
generate_unify(int_const(SiteNum), SiteNumVar, SiteNumVarGoal),
generate_call(ModuleInfo, "prepare_for_callback", 1,
[SiteNumVar], [], PrepareGoal),
goal_info_get_context(GoalInfo0, Context),
LineNumber = term__context_line(Context),
FileName0 = term__context_file(Context),
compress_filename(DeepInfo0, FileName0, FileName),
CallSite = callback(FileName, LineNumber, GoalPath),
goal_info_add_feature(GoalInfo0, impure, GoalInfo),
Goal = conj([
SiteNumVarGoal,
PrepareGoal,
Goal0
]) - GoalInfo,
DeepInfo = ((((DeepInfo0 ^ site_num_counter := SiteNumCounter)
^ vars := Vars)
^ var_types := VarTypes)
^ call_sites := DeepInfo0 ^ call_sites ++ [CallSite]).
:- pred compress_filename(deep_info::in, string::in, string::out) is det.
compress_filename(Deep, FileName0, FileName) :-
( FileName0 = Deep ^ proc_filename ->
FileName = ""
;
FileName = FileName0
).
:- type call_class
% For normal first order calls
---> normal(pred_proc_id)
% For calls to unify/2, compare/3 and
% compare_representation/3
; special(pred_proc_id, prog_var)
% For higher order and typeclass method calls
; generic(generic_call).
:- pred classify_call(module_info::in, hlds_goal_expr::in,
call_class::out) is det.
classify_call(ModuleInfo, Expr, Class) :-
( Expr = call(PredId, ProcId, Args, _, _, _) ->
(
lookup_builtin_pred_proc_id(ModuleInfo,
mercury_public_builtin_module, "unify",
predicate, 2, mode_no(0), PredId, _),
Args = [TypeInfoVar | _]
->
Class = special(proc(PredId, ProcId), TypeInfoVar)
;
lookup_builtin_pred_proc_id(ModuleInfo,
mercury_public_builtin_module, "compare",
predicate, 3, mode_no(0), PredId, _),
Args = [TypeInfoVar | _]
->
Class = special(proc(PredId, ProcId), TypeInfoVar)
;
lookup_builtin_pred_proc_id(ModuleInfo,
mercury_public_builtin_module,
"compare_representation", predicate, 3,
mode_no(0), PredId, _),
Args = [TypeInfoVar | _]
->
Class = special(proc(PredId, ProcId), TypeInfoVar)
;
Class = normal(proc(PredId, ProcId))
)
; Expr = generic_call(Generic, _, _, _) ->
Class = generic(Generic)
;
error("unexpected goal type in classify_call/2")
).
:- 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, DeepInfo0, DeepInfo) :-
list__chunk(CSNs, max_save_restore_vector_size, CSNChunks),
generate_recursion_counter_saves_and_restores_2(CSNChunks, CSDVar,
CallGoals, ExitGoals, FailGoals, ExtraVars,
DeepInfo0, 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, DeepInfo).
generate_recursion_counter_saves_and_restores_2([Chunk | Chunks], CSDVar,
CallGoals, ExitGoals, FailGoals, ExtraVars,
DeepInfo0, DeepInfo) :-
list__map_foldl(generate_depth_var, Chunk, DepthVars,
DeepInfo0, DeepInfo1),
% 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, CallVars1, CallGoals1, CallCellVar,
DeepInfo1, DeepInfo2),
generate_csn_vector(Length, Chunk, ExitVars1, ExitGoals1, ExitCellVar,
DeepInfo2, DeepInfo3),
generate_csn_vector(Length, Chunk, FailVars1, FailGoals1, FailCellVar,
DeepInfo3, DeepInfo4),
list__condense([CallVars1, ExitVars1, FailVars1], ExtraVars1),
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 = DeepInfo4 ^ module_info,
generate_call(ModuleInfo, CallPredName, Length + 2,
[CSDVar, CallCellVar | DepthVars], DepthVars, CallCellGoal),
generate_call(ModuleInfo, ExitPredName, Length + 2,
[CSDVar, ExitCellVar | DepthVars], [], ExitCellGoal),
generate_call(ModuleInfo, FailPredName, Length + 2,
[CSDVar, FailCellVar | DepthVars], [], FailCellGoal),
generate_recursion_counter_saves_and_restores_2(Chunks, CSDVar,
CallGoals2, ExitGoals2, FailGoals2, ExtraVars2,
DeepInfo4, DeepInfo),
list__append(CallGoals1, [CallCellGoal | CallGoals2], CallGoals),
list__append(ExitGoals1, [ExitCellGoal | ExitGoals2], ExitGoals),
list__append(FailGoals1, [FailCellGoal | FailGoals2], FailGoals),
list__append(ExtraVars1, ExtraVars2, ExtraVars).
:- pred generate_depth_var(int::in, prog_var::out,
deep_info::in, deep_info::out) is det.
generate_depth_var(CSN, DepthVar, DeepInfo0, DeepInfo) :-
Vars0 = DeepInfo0 ^ vars,
VarTypes0 = DeepInfo0 ^ var_types,
IntType = int_type,
VarName = string__format("Depth%d", [i(CSN)]),
varset__new_named_var(Vars0, VarName, DepthVar, Vars),
map__set(VarTypes0, DepthVar, IntType, VarTypes),
DeepInfo = (DeepInfo0 ^ vars := Vars) ^ var_types := VarTypes.
:- 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,
DeepInfo0, DeepInfo) :-
( CSNs = [CSN] ->
generate_single_csn_unify(CSN, CSNVar - UnifyGoal,
DeepInfo0, DeepInfo),
CSNVars = [CSNVar],
UnifyGoals = [UnifyGoal],
CellVar = CSNVar
;
require(Length =< max_save_restore_vector_size,
"generate_csn_vector_unifies: too long"),
list__map_foldl(generate_single_csn_unify, CSNs, CSNVarsGoals,
DeepInfo0, DeepInfo1),
InnerVars = assoc_list__keys(CSNVarsGoals),
InnerGoals = assoc_list__values(CSNVarsGoals),
generate_csn_vector_cell(Length, InnerVars, CellVar, CellGoal,
DeepInfo1, DeepInfo),
CSNVars = [CellVar | InnerVars],
UnifyGoals = list__append(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,
DeepInfo0, DeepInfo) :-
Vars0 = DeepInfo0 ^ vars,
VarTypes0 = DeepInfo0 ^ var_types,
varset__new_named_var(Vars0, "CSNCell", CellVar, Vars),
mercury_profiling_builtin_module(ProfilingBuiltin),
CellTypeName = string__format("call_site_nums_%d", [i(Length)]),
CellTypeId = qualified(ProfilingBuiltin, CellTypeName) - Length,
construct_type(CellTypeId, [], CellType),
map__set(VarTypes0, CellVar, CellType, VarTypes),
DeepInfo = (DeepInfo0 ^ vars := Vars) ^ var_types := VarTypes,
ConsId = cons(qualified(ProfilingBuiltin, CellTypeName), Length),
generate_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, DeepInfo0, DeepInfo) :-
Vars0 = DeepInfo0 ^ vars,
VarTypes0 = DeepInfo0 ^ var_types,
VarName = string__format("CSN%d", [i(CSN)]),
varset__new_named_var(Vars0, VarName, CSNVar, Vars),
map__set(VarTypes0, CSNVar, int_type, VarTypes),
DeepInfo = (DeepInfo0 ^ vars := Vars) ^ var_types := VarTypes,
generate_unify(int_const(CSN), CSNVar, UnifyGoal).
:- pred generate_call(module_info::in, string::in, int::in,
list(prog_var)::in, list(prog_var)::in, hlds_goal::out) is det.
generate_call(ModuleInfo, Name, Arity, ArgVars, OutputVars, Goal) :-
generate_call(ModuleInfo, Name, Arity, ArgVars, yes(OutputVars),
det, Goal).
:- pred generate_call(module_info::in, string::in, int::in, list(prog_var)::in,
maybe(list(prog_var))::in, determinism::in, hlds_goal::out) is det.
generate_call(ModuleInfo, Name, Arity, ArgVars, MaybeOutputVars, Detism,
Goal) :-
get_deep_profile_builtin_ppid(ModuleInfo, Name, Arity, PredId, ProcId),
NonLocals = list_to_set(ArgVars),
Ground = ground(shared, none),
(
MaybeOutputVars = yes(OutputVars),
map((pred(V::in, P::out) is det :-
P = V - Ground
), OutputVars, OutputInsts),
instmap_delta_from_assoc_list(OutputInsts, InstMapDelta)
;
MaybeOutputVars = no,
instmap_delta_init_unreachable(InstMapDelta)
),
GoalInfo = impure_init_goal_info(NonLocals, InstMapDelta, Detism),
Goal = call(PredId, ProcId, ArgVars, not_builtin, no,
unqualified(Name)) - GoalInfo.
:- pred generate_unify(cons_id::in, prog_var::in, hlds_goal::out) is det.
generate_unify(ConsId, Var, Goal) :-
Ground = ground(shared, none),
NonLocals = set__make_singleton_set(Var),
instmap_delta_from_assoc_list([Var - ground(shared, none)],
InstMapDelta),
Determinism = det,
goal_info_init(NonLocals, InstMapDelta, Determinism, pure, GoalInfo),
Goal = unify(Var, functor(ConsId, no, []),
(free -> Ground) - (Ground -> Ground),
construct(Var, ConsId, [], [], construct_statically([]),
cell_is_shared, no),
unify_context(explicit, [])) - GoalInfo.
:- pred generate_cell_unify(int::in, cons_id::in, list(prog_var)::in,
prog_var::in, hlds_goal::out) is det.
generate_cell_unify(Length, ConsId, Args, Var, Goal) :-
Ground = ground(shared, none),
NonLocals = set__list_to_set([Var | Args]),
instmap_delta_from_assoc_list([Var - Ground], InstMapDelta),
Determinism = det,
goal_info_init(NonLocals, InstMapDelta, Determinism, pure, GoalInfo),
ArgMode = ((free - Ground) -> (Ground - Ground)),
list__duplicate(Length, ArgMode, ArgModes),
Goal = unify(Var, functor(ConsId, no, Args),
(free -> Ground) - (Ground -> Ground),
construct(Var, ConsId, Args, ArgModes,
construct_statically([]), cell_is_shared, no),
unify_context(explicit, [])) - GoalInfo.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- pred get_deep_profile_builtin_ppid(module_info::in, string::in, int::in,
pred_id::out, proc_id::out) is det.
get_deep_profile_builtin_ppid(ModuleInfo, Name, Arity, PredId, ProcId) :-
mercury_profiling_builtin_module(ModuleName),
module_info_get_predicate_table(ModuleInfo, PredTable),
(
predicate_table_search_pred_m_n_a(PredTable,
is_fully_qualified, ModuleName, Name, Arity, PredIds)
->
(
PredIds = [],
error("get_deep_profile_builtin_ppid: no pred_id")
;
PredIds = [PredId],
predicate_table_get_preds(PredTable, Preds),
lookup(Preds, PredId, PredInfo),
ProcIds = pred_info_procids(PredInfo),
(
ProcIds = [],
error("get_deep_profile_builtin_ppid: " ++
"no proc_id")
;
ProcIds = [ProcId]
;
ProcIds = [_, _ | _],
error("get_deep_profile_builtin_ppid: " ++
"proc_id not unique")
)
;
PredIds = [_, _ | _],
error("get_deep_profile_builtin_ppid: " ++
"pred_id not unique")
)
;
format("couldn't find pred_id for `%s'/%d",
[s(Name), i(Arity)], Msg),
error(Msg)
).
%-----------------------------------------------------------------------------%
:- func impure_init_goal_info(set(prog_var), instmap_delta, determinism)
= hlds_goal_info.
impure_init_goal_info(NonLocals, InstMapDelta, Determinism) = GoalInfo :-
goal_info_init(NonLocals, InstMapDelta, Determinism, impure, GoalInfo).
:- func impure_reachable_init_goal_info(set(prog_var), determinism)
= hlds_goal_info.
impure_reachable_init_goal_info(NonLocals, Determinism) = GoalInfo :-
instmap_delta_init_reachable(InstMapDelta),
goal_info_init(NonLocals, InstMapDelta, Determinism, impure, GoalInfo).
:- func impure_unreachable_init_goal_info(set(prog_var), determinism)
= hlds_goal_info.
impure_unreachable_init_goal_info(NonLocals, Determinism) = GoalInfo :-
instmap_delta_init_unreachable(InstMapDelta),
goal_info_init(NonLocals, InstMapDelta, Determinism, impure, GoalInfo).
:- func goal_info_add_nonlocals_make_impure(hlds_goal_info, set(prog_var))
= hlds_goal_info.
goal_info_add_nonlocals_make_impure(GoalInfo0, NewNonLocals) = GoalInfo :-
goal_info_get_nonlocals(GoalInfo0, NonLocals0),
NonLocals = set__union(NonLocals0, NewNonLocals),
goal_info_set_nonlocals(GoalInfo0, NonLocals, GoalInfo1),
goal_info_add_feature(GoalInfo1, impure, GoalInfo).
:- func fail_goal_info = hlds_goal_info.
fail_goal_info = GoalInfo :-
instmap_delta_init_unreachable(InstMapDelta),
goal_info_init(set__init, InstMapDelta, failure, pure, GoalInfo).
%-----------------------------------------------------------------------------%