mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-18 07:15:19 +00:00
Estimated hours taken: 500 Branches: main Implement deep profiling; merge the changes on the deep2 branch back onto the trunk. The main documentation on the general architecture of the deep profiler is the deep profiling paper. doc/user_guide.texi: Document how to use the deep profiler. deep_profiler: deep_profiler/Mmakefile: A new directory holding the deep profiler and its mmakefile. Mmakefile: Add targets for the new directory. Add support for removing inappropriate files from directories. deep_profiler/interface.m: The deep profiler consists of two programs: mdprof_cgi.m, which acts as a CGI "script", and mdprof_server.m, which implements the server process that the CGI script talks to. Interface.m defines the interface between them. script/mdprof.in: A shell script template. ../configure uses it to generate mdprof, which is a wrapper around mdprof_cgi that tells it how to find mdprof_server. deep_profiler/mdprof_cgi.m: The CGI "script" program. deep_profiler/mdprof_server.m: The top level predicates of the server. deep_profiler/profile.m: The main data structures of the server and their operations. deep_profiler/read_profile.m: Code for reading in profiling data files. deep_profiler/startup.m: Code for post-processing the information in profiling data files, propagating costs from procedures to their ancestors and performing various kinds of summaries. deep_profiler/server.m: Code for responding to requests from the CGI script. deep_profiler/cliques.m: Code to find cliques in graphs. deep_profiler/array_util.m: deep_profiler/util.m: Utility predicates. deep_profiler/dense_bitset.m: An implementation of (part of) the set ADT with dense bit vectors. deep_profiler/measurements.m: Operations on profiling measurements. deep_profiler/timeout.m: An implementation of a timeout facility. deep_profiler/conf.m: Functions that depend on autoconfigured settings. configure.in: Find out what command to use to find the name of the local host. Install deep profiling versions of the standard library along with the other profiling versions. runtime/mercury_conf.h.in: Add some macros for deep_profiler/conf.m to use. library/profiling_builtin.m: runtime/mercury_deep_call_port_body.h: runtime/mercury_deep_leave_port_body.h: runtime/mercury_deep_redo_port_body.h: A new library module that implements deep profiling primitives. Some of these primitives have many versions, whose common code is factor is factored out in three new include files in the runtime. compiler/deep_profiling.m: New module to perform the program transformations described in the paper. compiler/notes/compiler_design.html: Document the new compiler module. compiler/mercury_compiler.m: Invoke the new module in deep profiling grades. Allow global static data to be generated by deep_profiling.m. compiler/options.m: Add options to turn on deep profiling and (for benchmarking purposes) control its implementation. Add an optiooption disable tailcall optimization in the LLDS backend, to help benchmarking deep profiling. compiler/jumpopt.m: compiler/optimize.m: Obey the option to disable tailcalls. compiler/handle_options.m: Handle the implications of deep profiling. compiler/modules.m: In deep profiling grades, automatically import profiling_builtin.m. compiler/prog_util.m: doc/Makefile: library/library.m: Handle the new builtin module. compiler/export.m: In deep profiling grades, wrap deep profiling code around exported procedures to handle the "unscheduled call" aspects of callbacks to Mercury from the foreign language. compiler/higher_order.m: profiler/demangle.m: util/demangle.c: When creating a name for a higher-order-specialized predicate, include the mode number in the name. compiler/add_trail_ops.m: compiler/type_util.m: Move c_pointer_type from add_trail_ops to type_util, so it can also be used by deep_profiling.m. compiler/hlds_goal.m: Add a new goal feature that marks a tail call, for use by deep_profiling.m. compiler/hlds_pred.m: Add a new field to proc_info structures for use by deep_profiling.m. Add a mechanism for getting proc_ids for procedure clones. Remove next_proc_id, an obsolete and unused predicate. compiler/hlds_data.m: Add a new cons_id to refer to the proc_static structure of a procedure. compiler/bytecode_gen.m: compiler/code_util.m: compiler/dependency_graph.m: compiler/hlds_out.m: compiler/mercury_to_mercury.m: compiler/ml_unify_gen.m: compiler/opt_debug.m: compiler/prog_rep.m: compiler/rl_exprn.m: compiler/switch_util.m: compiler/unify_gen.m: Trivial changes to handle the new cons_id, goal feature and/or proc_info argument. compiler/rtti.m: Add a utility predicate for extracting pred_id and proc_id from an rtti_proc_label, for use by hlds_out.m compiler/layout.m: compiler/layout_out.m: compiler/llds.m: compiler/llds_common.m: Add support for proc_static and call_site_static structures. compiler/layout_out.m: compiler/llds_out.m: Add code for the output of proc_static structures. compiler/code_util.m: Make code_util__make_proc_label_from_rtti a function, and export it. util/mkinit.c: compiler/llds_out.m: compiler/layout.m: compiler/modules.m: Add support for a fourth per-module C function, for writing out proc_static structures (and the call_site_static structures they contains). Since proc_static structures can be referred to from LLDS code (and not just from other static structures and compiler-generated C code), reorganize the declarations of static structures slightly. Change the schema for the name of the first per-module C function slightly, to make it the addition of the fourth function easier. The scheme now is: mercury__<modulename>__init mercury__<modulename>__init_type_tables mercury__<modulename>__init_debugger mercury__<modulename>__write_out_proc_statics Improve formatting of the generated C code. library/*.m: runtime/mercury.c: runtime/mercury_context.c: runtime/mercury_engine.c: runtime/mercury_ho_call.c: runtime/mercury_tabling.c: runtime/mercury_trace_base.c: runtime/mercury_wrapper.c: trace/mercrury_trace.[ch]: trace/mercrury_trace_declarative.c: trace/mercrury_trace_external.c: trace/mercrury_trace_internal.c: Conform to the new scheme for initialization functions for hand-written modules. compiler/mercury_compile.m: library/benchmarking.m: runtime/mercury_conf_param.h: runtime/mercury.h: runtime/mercury_engine.c: runtime/mercury_goto.c: runtime/mercury_grade.h: runtime/mercury_ho_call.c: runtime/mercury_label.[ch]: runtime/mercury_prof.[ch]: Add an MR_MPROF_ prefix in front of the C macros used to control the old profiler. compiler/handle_options.m: runtime/mercury_grade.h: scripts/canonical_grade.sh-subr: scripts/init_grade_options.sh-subr: scripts/parse_grade_options.sh-subr: Make deep profiling completely separate from the old profiling system, by making the deep profiling grade independent of MR_MPROF_PROFILE_TIME and the compiler option --profile-time. library/array.m: library/builtin.m: library/std_util.m: runtime/mercury_hand_unify_body.h: runtime/mercury_hand_compare_body.h: In deep profiling grades, wrap the deep profiling call, exit, fail and redo codes around the bodies of hand-written unification and comparison procedures. Make the reporting of array bounds violations switchable between making them fatal errors, as we currently, and reporting them by throwing an exception. Throwing an exception makes debugging code using arrays easier, but since exceptions aren't (yet) propagated across engine boundaries, we keep the old behaviour as the default; the new behaviour is for implementors. runtime/mercury_deep_profiling_hand.h: New file that defines macros for use in Mercury predicates whose definition is in hand-written C code. library/exception.m: runtime/mercury_exception_catch_body.h: runtime/mercury_stacks.h: In deep profiling grades, wrap the deep profiling call, exit, fail and redo codes around the bodies of the various modes of builtin_catch. Provide a function that C code can use to throw exceptions. library/benchmarking.m: library/exception.m: library/gc.m: library/std_util.m: runtime/mercury_context.[ch]: runtime/mercury_engine.[ch]: runtime/mercury_debug.c: runtime/mercury_deep_copy.c: runtime/mercury_overflow.h: runtime/mercury_regs.h: runtime/mercury_stacks.h: runtime/mercury_thread.c: runtime/mercury_wrapper.c: Add prefixes to the names of the fields in the engine and context structures, to make code using them easier to understand and modify. runtime/mercury_deep_profiling.[ch]: New module containing support functions for deep profiling and functions for writing out a deep profiling data file at the end of execution. runtime/mercury_debug.[ch]: Add support for debugging deep profiling. Add support for watching the value at a given address. Make the buffered/unbuffered nature of debugging output controllable via the -du option. Print register contents only if -dr is specified. runtime/mercury_goto.h: runtime/mercury_std.h: Use the macros in mercury_std.h instead of defining local variants. runtime/mercury_goto.h: runtime/mercury_stack_layout.h: runtime/mercury_stack_trace.c: runtime/mercury_tabling.c: trace/mercury_trace.c: trace/mercury_trace_declarative.c: trace/mercury_trace_external.c: trace/mercury_trace_vars.c: Standardize some of the macro names with those used in the debugger paper. runtime/mercury_heap.h: Add support for memory profiling with the deep profiler. runtime/mercury_prof.[ch]: runtime/mercury_prof_time.[ch]: Move the functionality that both the old profiler and the deep profiler need into the new module mercury_prof_time. Leave mercury_prof containing stuff that is only relevant to the old profiler. runtime/mercury_prof.[ch]: runtime/mercury_strerror.[ch]: Move the definition of strerror from mercury_prof to its own file. runtime/mercury_wrapper.[ch]: Add support for deep profiling. Add suppory for controlling whether debugging output is buffered or not. Add support for watching the value at a given address. runtime/Mmakefile: Mention all the added files. scripts/mgnuc.in: Add an option for turning on deep profiling. Add options for controlling the details of deep profiling. These are not documented because they are intended only for benchmarking the deep profiler itself, for the paper; they are not for general use. tools/bootcheck: Compile the deep_profiler directory as well as the other directories containing Mercury code. Turn off the creation of deep profiling data files during bootcheck, since all but one of these in each directory will be overwritten anyway. Add support for turning on --keep-objs by default in a workspace. tools/speedtest: Preserve any deep profiling data files created by the tests. trace/mercury_trace.c: Trap attempts to perform retries in deep profiling grades, since they would lead to core dumps otherwise. util/Mmakefile: Avoid compile-time warnings when compiling getopt. tests/*/Mmakefile: tests/*/*/Mmakefile: In deep profiling grades, switch off the tests that test features that don't work with deep profiling, either by design or because the combination hasn't been implemented yet.
981 lines
35 KiB
Mathematica
981 lines
35 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1994-2001 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% file: code_util.m.
|
|
%
|
|
% various utilities routines for code generation and recognition
|
|
% of builtins.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module code_util.
|
|
|
|
:- interface.
|
|
|
|
:- import_module prog_data, hlds_module, hlds_pred, hlds_goal, hlds_data.
|
|
:- import_module rtti, llds.
|
|
|
|
:- import_module bool, list, std_util.
|
|
|
|
% Create a code address which holds the address of the specified
|
|
% procedure.
|
|
% The `immed' argument should be `no' if the the caller wants the
|
|
% returned address to be valid from everywhere in the program.
|
|
% If being valid from within the current procedure is enough,
|
|
% this argument should be `yes' wrapped around the value of the
|
|
% --procs-per-c-function option and the current procedure id.
|
|
% Using an address that is only valid from within the current
|
|
% procedure may make jumps more efficient.
|
|
|
|
:- type immed == maybe(pair(int, pred_proc_id)).
|
|
|
|
:- pred code_util__make_entry_label(module_info, pred_id, proc_id,
|
|
immed, code_addr).
|
|
:- mode code_util__make_entry_label(in, in, in, in, out) is det.
|
|
|
|
:- pred code_util__make_entry_label_from_rtti(rtti_proc_label, immed,
|
|
code_addr).
|
|
:- mode code_util__make_entry_label_from_rtti(in, in, out) is det.
|
|
|
|
% Create a label which holds the address of the specified procedure,
|
|
% which must be defined in the current module (procedures that are
|
|
% imported from other modules have representations only as code_addrs,
|
|
% not as labels, since their address is not known at C compilation
|
|
% time).
|
|
% The fourth argument has the same meaning as for
|
|
% code_util__make_entry_label.
|
|
|
|
:- pred code_util__make_local_entry_label(module_info, pred_id, proc_id,
|
|
immed, label).
|
|
:- mode code_util__make_local_entry_label(in, in, in, in, out) is det.
|
|
|
|
% Create a label internal to a Mercury procedure.
|
|
:- pred code_util__make_internal_label(module_info, pred_id, proc_id, int,
|
|
label).
|
|
:- mode code_util__make_internal_label(in, in, in, in, out) is det.
|
|
|
|
:- pred code_util__make_proc_label(module_info, pred_id, proc_id, proc_label).
|
|
:- mode code_util__make_proc_label(in, in, in, out) is det.
|
|
|
|
:- func code_util__make_proc_label_from_rtti(rtti_proc_label) = proc_label.
|
|
|
|
% code_util__make_user_proc_label(ModuleName, PredIsImported,
|
|
% PredOrFunc, ModuleName, PredName, Arity, ProcId, Label):
|
|
% Make a proc_label for a user-defined procedure.
|
|
%
|
|
% The PredIsImported argument should be the result of
|
|
% calling pred_info_is_imported.
|
|
|
|
:- pred code_util__make_user_proc_label(module_name, bool,
|
|
pred_or_func, module_name, string, arity, proc_id, proc_label).
|
|
:- mode code_util__make_user_proc_label(in, in,
|
|
in, in, in, in, in, out) is det.
|
|
|
|
:- pred code_util__make_uni_label(module_info, type_id, proc_id, proc_label).
|
|
:- mode code_util__make_uni_label(in, in, in, out) is det.
|
|
|
|
:- pred code_util__extract_proc_label_from_code_addr(code_addr, proc_label).
|
|
:- mode code_util__extract_proc_label_from_code_addr(in, out) is det.
|
|
|
|
:- pred code_util__extract_proc_label_from_label(label, proc_label).
|
|
:- mode code_util__extract_proc_label_from_label(in, out) is det.
|
|
|
|
:- pred code_util__arg_loc_to_register(arg_loc, lval).
|
|
:- mode code_util__arg_loc_to_register(in, out) is det.
|
|
|
|
:- pred code_util__max_mentioned_reg(list(lval), int).
|
|
:- mode code_util__max_mentioned_reg(in, out) is det.
|
|
|
|
% Determine whether a goal might allocate some heap space,
|
|
% i.e. whether it contains any construction unifications
|
|
% or predicate calls. BEWARE that this predicate is only
|
|
% an approximation, used to decide whether or not to try to
|
|
% reclaim the heap space; currently it fails even for some
|
|
% goals which do allocate heap space, such as construction
|
|
% of boxed constants.
|
|
|
|
:- pred code_util__goal_may_allocate_heap(hlds_goal).
|
|
:- mode code_util__goal_may_allocate_heap(in) is semidet.
|
|
|
|
:- pred code_util__goal_list_may_allocate_heap(list(hlds_goal)).
|
|
:- mode code_util__goal_list_may_allocate_heap(in) is semidet.
|
|
|
|
:- pred code_util__goal_may_alloc_temp_frame(hlds_goal).
|
|
:- mode code_util__goal_may_alloc_temp_frame(in) is semidet.
|
|
|
|
% Negate a condition.
|
|
% This is used mostly just to make the generated code more readable.
|
|
|
|
:- pred code_util__neg_rval(rval, rval).
|
|
:- mode code_util__neg_rval(in, out) is det.
|
|
|
|
:- pred code_util__negate_the_test(list(instruction), list(instruction)).
|
|
:- mode code_util__negate_the_test(in, out) is det.
|
|
|
|
% code_util__compiler_generated(PredInfo) succeeds iff
|
|
% the PredInfo is for a compiler generated instance of a
|
|
% type-specific special_pred (i.e. one of the __Unify__,
|
|
% __Index__, or __Compare__ predicates generated as a
|
|
% type-specific instance of unify/2, index/2, or compare/3).
|
|
%
|
|
% XXX The name of this predicate is misleading, because there
|
|
% are other kinds of compiler-generated predicates, e.g. those
|
|
% for lambda expressions, those generated by higher-order
|
|
% specialization, ordinary type specialization, deforestation,
|
|
% etc., for which this predicate does not succeed.
|
|
|
|
:- pred code_util__compiler_generated(pred_info).
|
|
:- mode code_util__compiler_generated(in) is semidet.
|
|
|
|
:- pred code_util__predinfo_is_builtin(pred_info).
|
|
:- mode code_util__predinfo_is_builtin(in) is semidet.
|
|
|
|
:- pred code_util__builtin_state(module_info, pred_id, proc_id, builtin_state).
|
|
:- mode code_util__builtin_state(in, in, in, out) is det.
|
|
|
|
% Find out how a function symbol (constructor) is represented
|
|
% in the given type.
|
|
|
|
:- pred code_util__cons_id_to_tag(cons_id, type, module_info, cons_tag).
|
|
:- mode code_util__cons_id_to_tag(in, in, in, out) is det.
|
|
|
|
% Succeed if the given goal cannot encounter a context
|
|
% that causes any variable to be flushed to its stack slot.
|
|
% If such a goal needs a resume point, and that resume point cannot
|
|
% be backtracked to once control leaves the goal, then the only entry
|
|
% point we need for the resume point is the one with the resume
|
|
% variables in their original locations.
|
|
|
|
:- pred code_util__cannot_stack_flush(hlds_goal).
|
|
:- mode code_util__cannot_stack_flush(in) is semidet.
|
|
|
|
% Succeed if the given goal cannot fail before encountering a context
|
|
% that forces all variables to be flushed to their stack slots.
|
|
% If such a goal needs a resume point, the only entry point we need
|
|
% is the stack entry point.
|
|
|
|
:- pred code_util__cannot_fail_before_stack_flush(hlds_goal).
|
|
:- mode code_util__cannot_fail_before_stack_flush(in) is semidet.
|
|
|
|
% code_util__count_recursive_calls(Goal, PredId, ProcId, Min, Max)
|
|
% Given that we are in predicate PredId and procedure ProcId,
|
|
% return the minimum and maximum number of recursive calls that
|
|
% an execution of Goal may encounter.
|
|
|
|
:- pred code_util__count_recursive_calls(hlds_goal, pred_id, proc_id,
|
|
int, int).
|
|
:- mode code_util__count_recursive_calls(in, in, in, out, out) is det.
|
|
|
|
% These predicates return the set of lvals referenced in an rval
|
|
% and an lval respectively. Lvals referenced indirectly through
|
|
% lvals of the form var(_) are not counted.
|
|
|
|
:- pred code_util__lvals_in_rval(rval, list(lval)).
|
|
:- mode code_util__lvals_in_rval(in, out) is det.
|
|
|
|
:- pred code_util__lvals_in_lval(lval, list(lval)).
|
|
:- mode code_util__lvals_in_lval(in, out) is det.
|
|
|
|
:- pred code_util__lvals_in_lvals(list(lval), list(lval)).
|
|
:- mode code_util__lvals_in_lvals(in, out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module prog_util, type_util, special_pred, builtin_ops, code_model.
|
|
|
|
:- import_module char, int, string, set, map, term, varset.
|
|
:- import_module require, std_util, assoc_list.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_util__make_entry_label(ModuleInfo, PredId, ProcId, Immed, ProcAddr) :-
|
|
RttiProcLabel = rtti__make_proc_label(ModuleInfo, PredId, ProcId),
|
|
code_util__make_entry_label_from_rtti(RttiProcLabel, Immed, ProcAddr).
|
|
|
|
code_util__make_entry_label_from_rtti(RttiProcLabel, Immed, ProcAddr) :-
|
|
(
|
|
(
|
|
RttiProcLabel^is_imported = yes
|
|
;
|
|
RttiProcLabel^is_pseudo_imported = yes,
|
|
% only the (in, in) mode of unification is imported
|
|
hlds_pred__in_in_unification_proc_id(
|
|
RttiProcLabel^proc_id)
|
|
)
|
|
->
|
|
code_util__make_proc_label_from_rtti(RttiProcLabel)
|
|
= ProcLabel,
|
|
ProcAddr = imported(ProcLabel)
|
|
;
|
|
code_util__make_local_entry_label_from_rtti(RttiProcLabel,
|
|
Immed, Label),
|
|
ProcAddr = label(Label)
|
|
).
|
|
|
|
code_util__make_local_entry_label(ModuleInfo, PredId, ProcId, Immed, Label) :-
|
|
RttiProcLabel = rtti__make_proc_label(ModuleInfo, PredId, ProcId),
|
|
code_util__make_local_entry_label_from_rtti(RttiProcLabel,
|
|
Immed, Label).
|
|
|
|
:- pred code_util__make_local_entry_label_from_rtti(rtti_proc_label, immed,
|
|
label).
|
|
:- mode code_util__make_local_entry_label_from_rtti(in, in, out) is det.
|
|
|
|
code_util__make_local_entry_label_from_rtti(RttiProcLabel, Immed, Label) :-
|
|
code_util__make_proc_label_from_rtti(RttiProcLabel) = ProcLabel,
|
|
(
|
|
Immed = no,
|
|
% If we want to define the label or use it to put it
|
|
% into a data structure, a label that is usable only
|
|
% within the current C module won't do.
|
|
( RttiProcLabel^is_exported = yes ->
|
|
Label = exported(ProcLabel)
|
|
;
|
|
Label = local(ProcLabel)
|
|
)
|
|
;
|
|
Immed = yes(ProcsPerFunc - proc(CurPredId, CurProcId)),
|
|
choose_local_label_type(ProcsPerFunc, CurPredId, CurProcId,
|
|
RttiProcLabel^pred_id, RttiProcLabel^proc_id,
|
|
ProcLabel, Label)
|
|
).
|
|
|
|
|
|
:- pred choose_local_label_type(int, pred_id, proc_id,
|
|
pred_id, proc_id, proc_label, label).
|
|
:- mode choose_local_label_type(in, in, in, in, in, in, out) is det.
|
|
|
|
choose_local_label_type(ProcsPerFunc, CurPredId, CurProcId,
|
|
PredId, ProcId, ProcLabel, Label) :-
|
|
(
|
|
% If we want to branch to the label now,
|
|
% we prefer a form that are usable only within
|
|
% the current C module, since it is likely
|
|
% to be faster.
|
|
(
|
|
ProcsPerFunc = 0
|
|
;
|
|
PredId = CurPredId,
|
|
ProcId = CurProcId
|
|
)
|
|
->
|
|
Label = c_local(ProcLabel)
|
|
;
|
|
Label = local(ProcLabel)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
code_util__make_internal_label(ModuleInfo, PredId, ProcId, LabelNum, Label) :-
|
|
code_util__make_proc_label(ModuleInfo, PredId, ProcId, ProcLabel),
|
|
Label = local(LabelNum, ProcLabel).
|
|
|
|
code_util__make_proc_label(ModuleInfo, PredId, ProcId, ProcLabel) :-
|
|
RttiProcLabel = rtti__make_proc_label(ModuleInfo, PredId, ProcId),
|
|
code_util__make_proc_label_from_rtti(RttiProcLabel) = ProcLabel.
|
|
|
|
code_util__make_proc_label_from_rtti(RttiProcLabel) = ProcLabel :-
|
|
RttiProcLabel = rtti_proc_label(PredOrFunc, ThisModule,
|
|
PredModule, PredName, PredArity, ArgTypes, _PredId, ProcId,
|
|
_VarSet, _HeadVars, _ArgModes, _CodeModel,
|
|
IsImported, _IsPseudoImported, _IsExported,
|
|
IsSpecialPredInstance),
|
|
(
|
|
IsSpecialPredInstance = yes
|
|
->
|
|
(
|
|
special_pred_get_type(PredName, ArgTypes, Type),
|
|
type_to_type_id(Type, TypeId, _),
|
|
% All type_ids other than tuples here should be
|
|
% module qualified, since builtin types are
|
|
% handled separately in polymorphism.m.
|
|
(
|
|
TypeId = unqualified(TypeName) - _,
|
|
type_id_is_tuple(TypeId),
|
|
mercury_public_builtin_module(TypeModule)
|
|
;
|
|
TypeId = qualified(TypeModule, TypeName) - _
|
|
)
|
|
->
|
|
TypeId = _ - TypeArity,
|
|
(
|
|
ThisModule \= TypeModule,
|
|
PredName = "__Unify__",
|
|
\+ hlds_pred__in_in_unification_proc_id(ProcId)
|
|
->
|
|
DefiningModule = ThisModule
|
|
;
|
|
DefiningModule = TypeModule
|
|
),
|
|
ProcLabel = special_proc(DefiningModule, PredName,
|
|
TypeModule, TypeName, TypeArity, ProcId)
|
|
;
|
|
string__append_list(["code_util__make_proc_label:\n",
|
|
"cannot make label for special pred `",
|
|
PredName, "'"], ErrorMessage),
|
|
error(ErrorMessage)
|
|
)
|
|
;
|
|
code_util__make_user_proc_label(ThisModule, IsImported,
|
|
PredOrFunc, PredModule, PredName, PredArity,
|
|
ProcId, ProcLabel)
|
|
).
|
|
|
|
code_util__make_user_proc_label(ThisModule, PredIsImported,
|
|
PredOrFunc, PredModule, PredName, PredArity,
|
|
ProcId, ProcLabel) :-
|
|
|
|
(
|
|
% Work out which module supplies the code for
|
|
% the predicate.
|
|
ThisModule \= PredModule,
|
|
PredIsImported = no
|
|
->
|
|
% This predicate is a specialized version of
|
|
% a pred from a `.opt' file.
|
|
DefiningModule = ThisModule
|
|
;
|
|
DefiningModule = PredModule
|
|
),
|
|
ProcLabel = proc(DefiningModule, PredOrFunc,
|
|
PredModule, PredName, PredArity, ProcId).
|
|
|
|
code_util__make_uni_label(ModuleInfo, TypeId, UniModeNum, ProcLabel) :-
|
|
module_info_name(ModuleInfo, ModuleName),
|
|
( TypeId = qualified(TypeModule, TypeName) - Arity ->
|
|
( hlds_pred__in_in_unification_proc_id(UniModeNum) ->
|
|
Module = TypeModule
|
|
;
|
|
Module = ModuleName
|
|
),
|
|
ProcLabel = special_proc(Module, "__Unify__", TypeModule,
|
|
TypeName, Arity, UniModeNum)
|
|
;
|
|
error("code_util__make_uni_label: unqualified type_id")
|
|
).
|
|
|
|
code_util__extract_proc_label_from_code_addr(CodeAddr, ProcLabel) :-
|
|
( code_util__proc_label_from_code_addr(CodeAddr, ProcLabelPrime) ->
|
|
ProcLabel = ProcLabelPrime
|
|
;
|
|
error("code_util__extract_label_from_code_addr failed")
|
|
).
|
|
|
|
:- pred code_util__proc_label_from_code_addr(code_addr::in,
|
|
proc_label::out) is semidet.
|
|
|
|
code_util__proc_label_from_code_addr(CodeAddr, ProcLabel) :-
|
|
(
|
|
CodeAddr = label(Label),
|
|
code_util__extract_proc_label_from_label(Label, ProcLabel)
|
|
;
|
|
CodeAddr = imported(ProcLabel)
|
|
).
|
|
|
|
code_util__extract_proc_label_from_label(local(_, ProcLabel), ProcLabel).
|
|
code_util__extract_proc_label_from_label(c_local(ProcLabel), ProcLabel).
|
|
code_util__extract_proc_label_from_label(local(ProcLabel), ProcLabel).
|
|
code_util__extract_proc_label_from_label(exported(ProcLabel), ProcLabel).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
code_util__arg_loc_to_register(ArgLoc, reg(r, ArgLoc)).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
code_util__max_mentioned_reg(Lvals, MaxRegNum) :-
|
|
code_util__max_mentioned_reg_2(Lvals, 0, MaxRegNum).
|
|
|
|
:- pred code_util__max_mentioned_reg_2(list(lval)::in, int::in, int::out)
|
|
is det.
|
|
|
|
code_util__max_mentioned_reg_2([], MaxRegNum, MaxRegNum).
|
|
code_util__max_mentioned_reg_2([Lval | Lvals], MaxRegNum0, MaxRegNum) :-
|
|
( Lval = reg(r, N) ->
|
|
int__max(MaxRegNum0, N, MaxRegNum1)
|
|
;
|
|
MaxRegNum1 = MaxRegNum0
|
|
),
|
|
code_util__max_mentioned_reg_2(Lvals, MaxRegNum1, MaxRegNum).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
code_util__predinfo_is_builtin(PredInfo) :-
|
|
pred_info_module(PredInfo, ModuleName),
|
|
pred_info_name(PredInfo, PredName),
|
|
pred_info_arity(PredInfo, Arity),
|
|
hlds_pred__initial_proc_id(ProcId),
|
|
code_util__is_inline_builtin(ModuleName, PredName, ProcId, Arity).
|
|
|
|
code_util__builtin_state(ModuleInfo, PredId, ProcId, BuiltinState) :-
|
|
module_info_pred_info(ModuleInfo, PredId, PredInfo),
|
|
pred_info_module(PredInfo, ModuleName),
|
|
pred_info_name(PredInfo, PredName),
|
|
pred_info_arity(PredInfo, Arity),
|
|
( code_util__is_inline_builtin(ModuleName, PredName, ProcId, Arity) ->
|
|
BuiltinState = inline_builtin
|
|
;
|
|
BuiltinState = not_builtin
|
|
).
|
|
|
|
:- pred code_util__is_inline_builtin(module_name, string, proc_id, arity).
|
|
:- mode code_util__is_inline_builtin(in, in, in, in) is semidet.
|
|
|
|
code_util__is_inline_builtin(ModuleName, PredName, ProcId, Arity) :-
|
|
Arity =< 3,
|
|
prog_varset_init(VarSet),
|
|
varset__new_vars(VarSet, Arity, Args, _),
|
|
builtin_ops__translate_builtin(ModuleName, PredName, ProcId, Args, _).
|
|
|
|
:- pred prog_varset_init(prog_varset::out) is det.
|
|
prog_varset_init(VarSet) :- varset__init(VarSet).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% XXX The name of this predicate is misleading -- see the comment
|
|
% in the declaration.
|
|
code_util__compiler_generated(PredInfo) :-
|
|
pred_info_name(PredInfo, PredName),
|
|
pred_info_arity(PredInfo, PredArity),
|
|
special_pred_name_arity(_, _, PredName, PredArity).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
code_util__goal_may_allocate_heap(Goal) :-
|
|
code_util__goal_may_allocate_heap(Goal, yes).
|
|
|
|
code_util__goal_list_may_allocate_heap(Goals) :-
|
|
code_util__goal_list_may_allocate_heap(Goals, yes).
|
|
|
|
:- pred code_util__goal_may_allocate_heap(hlds_goal::in, bool::out) is det.
|
|
|
|
code_util__goal_may_allocate_heap(Goal - _GoalInfo, May) :-
|
|
code_util__goal_may_allocate_heap_2(Goal, May).
|
|
|
|
:- pred code_util__goal_may_allocate_heap_2(hlds_goal_expr::in, bool::out)
|
|
is det.
|
|
|
|
code_util__goal_may_allocate_heap_2(generic_call(_, _, _, _), yes).
|
|
code_util__goal_may_allocate_heap_2(call(_, _, _, Builtin, _, _), May) :-
|
|
( Builtin = inline_builtin ->
|
|
May = no
|
|
;
|
|
May = yes
|
|
).
|
|
code_util__goal_may_allocate_heap_2(unify(_, _, _, Unification, _), May) :-
|
|
( Unification = construct(_,_,Args,_,_,_,_), Args = [_|_] ->
|
|
May = yes
|
|
;
|
|
May = no
|
|
).
|
|
% We cannot safely say that a foreign code fragment does not
|
|
% allocate memory without knowing all the #defined macros that
|
|
% expand to incr_hp and variants thereof.
|
|
% XXX although you could make it an attribute of the foreign code and
|
|
% trust the programmer
|
|
code_util__goal_may_allocate_heap_2(foreign_proc(_,_,_,_,_,_,_), yes).
|
|
code_util__goal_may_allocate_heap_2(some(_Vars, _, Goal), May) :-
|
|
code_util__goal_may_allocate_heap(Goal, May).
|
|
code_util__goal_may_allocate_heap_2(not(Goal), May) :-
|
|
code_util__goal_may_allocate_heap(Goal, May).
|
|
code_util__goal_may_allocate_heap_2(conj(Goals), May) :-
|
|
code_util__goal_list_may_allocate_heap(Goals, May).
|
|
code_util__goal_may_allocate_heap_2(par_conj(_, _), yes).
|
|
code_util__goal_may_allocate_heap_2(disj(Goals, _), May) :-
|
|
code_util__goal_list_may_allocate_heap(Goals, May).
|
|
code_util__goal_may_allocate_heap_2(switch(_Var, _Det, Cases, _), May) :-
|
|
code_util__cases_may_allocate_heap(Cases, May).
|
|
code_util__goal_may_allocate_heap_2(if_then_else(_Vars, C, T, E, _), May) :-
|
|
( code_util__goal_may_allocate_heap(C, yes) ->
|
|
May = yes
|
|
; code_util__goal_may_allocate_heap(T, yes) ->
|
|
May = yes
|
|
;
|
|
code_util__goal_may_allocate_heap(E, May)
|
|
).
|
|
code_util__goal_may_allocate_heap_2(shorthand(ShorthandGoal), May) :-
|
|
code_util__goal_may_allocate_heap_2_shorthand(ShorthandGoal, May).
|
|
|
|
:- pred code_util__goal_may_allocate_heap_2_shorthand(shorthand_goal_expr::in,
|
|
bool::out) is det.
|
|
|
|
code_util__goal_may_allocate_heap_2_shorthand(bi_implication(G1, G2), May) :-
|
|
( code_util__goal_may_allocate_heap(G1, yes) ->
|
|
May = yes
|
|
;
|
|
code_util__goal_may_allocate_heap(G2, May)
|
|
).
|
|
|
|
|
|
|
|
:- pred code_util__goal_list_may_allocate_heap(list(hlds_goal)::in, bool::out)
|
|
is det.
|
|
|
|
code_util__goal_list_may_allocate_heap([], no).
|
|
code_util__goal_list_may_allocate_heap([Goal | Goals], May) :-
|
|
( code_util__goal_may_allocate_heap(Goal, yes) ->
|
|
May = yes
|
|
;
|
|
code_util__goal_list_may_allocate_heap(Goals, May)
|
|
).
|
|
|
|
:- pred code_util__cases_may_allocate_heap(list(case)::in, bool::out) is det.
|
|
|
|
code_util__cases_may_allocate_heap([], no).
|
|
code_util__cases_may_allocate_heap([case(_, Goal) | Cases], May) :-
|
|
( code_util__goal_may_allocate_heap(Goal, yes) ->
|
|
May = yes
|
|
;
|
|
code_util__cases_may_allocate_heap(Cases, May)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
code_util__goal_may_alloc_temp_frame(Goal) :-
|
|
code_util__goal_may_alloc_temp_frame(Goal, yes).
|
|
|
|
:- pred code_util__goal_may_alloc_temp_frame(hlds_goal::in, bool::out) is det.
|
|
|
|
code_util__goal_may_alloc_temp_frame(Goal - _GoalInfo, May) :-
|
|
code_util__goal_may_alloc_temp_frame_2(Goal, May).
|
|
|
|
:- pred code_util__goal_may_alloc_temp_frame_2(hlds_goal_expr::in, bool::out)
|
|
is det.
|
|
|
|
code_util__goal_may_alloc_temp_frame_2(generic_call(_, _, _, _), no).
|
|
code_util__goal_may_alloc_temp_frame_2(call(_, _, _, _, _, _), no).
|
|
code_util__goal_may_alloc_temp_frame_2(unify(_, _, _, _, _), no).
|
|
% We cannot safely say that a foreign code fragment does not allocate
|
|
% temporary nondet frames without knowing all the #defined macros
|
|
% that expand to mktempframe and variants thereof. The performance
|
|
% impact of being too conservative is probably not too bad.
|
|
code_util__goal_may_alloc_temp_frame_2(foreign_proc(_,_,_,_,_,_,_),
|
|
yes).
|
|
code_util__goal_may_alloc_temp_frame_2(some(_Vars, _, Goal), May) :-
|
|
Goal = _ - GoalInfo,
|
|
goal_info_get_code_model(GoalInfo, CodeModel),
|
|
( CodeModel = model_non ->
|
|
May = yes
|
|
;
|
|
code_util__goal_may_alloc_temp_frame(Goal, May)
|
|
).
|
|
code_util__goal_may_alloc_temp_frame_2(not(Goal), May) :-
|
|
code_util__goal_may_alloc_temp_frame(Goal, May).
|
|
code_util__goal_may_alloc_temp_frame_2(conj(Goals), May) :-
|
|
code_util__goal_list_may_alloc_temp_frame(Goals, May).
|
|
code_util__goal_may_alloc_temp_frame_2(par_conj(Goals, _), May) :-
|
|
code_util__goal_list_may_alloc_temp_frame(Goals, May).
|
|
code_util__goal_may_alloc_temp_frame_2(disj(Goals, _), May) :-
|
|
code_util__goal_list_may_alloc_temp_frame(Goals, May).
|
|
code_util__goal_may_alloc_temp_frame_2(switch(_Var, _Det, Cases, _), May) :-
|
|
code_util__cases_may_alloc_temp_frame(Cases, May).
|
|
code_util__goal_may_alloc_temp_frame_2(if_then_else(_Vars, C, T, E, _), May) :-
|
|
( code_util__goal_may_alloc_temp_frame(C, yes) ->
|
|
May = yes
|
|
; code_util__goal_may_alloc_temp_frame(T, yes) ->
|
|
May = yes
|
|
;
|
|
code_util__goal_may_alloc_temp_frame(E, May)
|
|
).
|
|
code_util__goal_may_alloc_temp_frame_2(shorthand(ShorthandGoal), May) :-
|
|
code_util__goal_may_alloc_temp_frame_2_shorthand(ShorthandGoal,May).
|
|
|
|
:- pred code_util__goal_may_alloc_temp_frame_2_shorthand(
|
|
shorthand_goal_expr::in, bool::out) is det.
|
|
|
|
code_util__goal_may_alloc_temp_frame_2_shorthand(bi_implication(G1, G2),
|
|
May) :-
|
|
( code_util__goal_may_alloc_temp_frame(G1, yes) ->
|
|
May = yes
|
|
;
|
|
code_util__goal_may_alloc_temp_frame(G2, May)
|
|
).
|
|
|
|
|
|
:- pred code_util__goal_list_may_alloc_temp_frame(list(hlds_goal)::in,
|
|
bool::out) is det.
|
|
|
|
code_util__goal_list_may_alloc_temp_frame([], no).
|
|
code_util__goal_list_may_alloc_temp_frame([Goal | Goals], May) :-
|
|
( code_util__goal_may_alloc_temp_frame(Goal, yes) ->
|
|
May = yes
|
|
;
|
|
code_util__goal_list_may_alloc_temp_frame(Goals, May)
|
|
).
|
|
|
|
:- pred code_util__cases_may_alloc_temp_frame(list(case)::in, bool::out)
|
|
is det.
|
|
|
|
code_util__cases_may_alloc_temp_frame([], no).
|
|
code_util__cases_may_alloc_temp_frame([case(_, Goal) | Cases], May) :-
|
|
( code_util__goal_may_alloc_temp_frame(Goal, yes) ->
|
|
May = yes
|
|
;
|
|
code_util__cases_may_alloc_temp_frame(Cases, May)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Negate a condition.
|
|
% This is used mostly just to make the generated code more readable.
|
|
|
|
code_util__neg_rval(Rval, NegRval) :-
|
|
( code_util__neg_rval_2(Rval, NegRval0) ->
|
|
NegRval = NegRval0
|
|
;
|
|
NegRval = unop(not, Rval)
|
|
).
|
|
|
|
:- pred code_util__neg_rval_2(rval, rval).
|
|
:- mode code_util__neg_rval_2(in, out) is semidet.
|
|
|
|
code_util__neg_rval_2(const(Const), const(NegConst)) :-
|
|
(
|
|
Const = true, NegConst = false
|
|
;
|
|
Const = false, NegConst = true
|
|
).
|
|
code_util__neg_rval_2(unop(not, Rval), Rval).
|
|
code_util__neg_rval_2(binop(Op, X, Y), binop(NegOp, X, Y)) :-
|
|
code_util__neg_op(Op, NegOp).
|
|
|
|
:- pred code_util__neg_op(binary_op, binary_op).
|
|
:- mode code_util__neg_op(in, out) is semidet.
|
|
|
|
code_util__neg_op(eq, ne).
|
|
code_util__neg_op(ne, eq).
|
|
code_util__neg_op(<, >=).
|
|
code_util__neg_op(<=, >).
|
|
code_util__neg_op(>, <=).
|
|
code_util__neg_op(>=, <).
|
|
code_util__neg_op(str_eq, str_ne).
|
|
code_util__neg_op(str_ne, str_eq).
|
|
code_util__neg_op(str_lt, str_ge).
|
|
code_util__neg_op(str_le, str_gt).
|
|
code_util__neg_op(str_gt, str_le).
|
|
code_util__neg_op(str_ge, str_lt).
|
|
code_util__neg_op(float_eq, float_ne).
|
|
code_util__neg_op(float_ne, float_eq).
|
|
code_util__neg_op(float_lt, float_ge).
|
|
code_util__neg_op(float_le, float_gt).
|
|
code_util__neg_op(float_gt, float_le).
|
|
code_util__neg_op(float_ge, float_lt).
|
|
|
|
code_util__negate_the_test([], _) :-
|
|
error("code_util__negate_the_test on empty list").
|
|
code_util__negate_the_test([Instr0 | Instrs0], Instrs) :-
|
|
( Instr0 = if_val(Test, Target) - Comment ->
|
|
code_util__neg_rval(Test, NewTest),
|
|
Instrs = [if_val(NewTest, Target) - Comment]
|
|
;
|
|
code_util__negate_the_test(Instrs0, Instrs1),
|
|
Instrs = [Instr0 | Instrs1]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
code_util__cons_id_to_tag(int_const(X), _, _, int_constant(X)).
|
|
code_util__cons_id_to_tag(float_const(X), _, _, float_constant(X)).
|
|
code_util__cons_id_to_tag(string_const(X), _, _, string_constant(X)).
|
|
code_util__cons_id_to_tag(code_addr_const(P,M), _, _, code_addr_constant(P,M)).
|
|
code_util__cons_id_to_tag(pred_const(P,M,E), _, _, pred_closure_tag(P,M,E)).
|
|
code_util__cons_id_to_tag(type_ctor_info_const(M,T,A), _, _,
|
|
type_ctor_info_constant(M,T,A)).
|
|
code_util__cons_id_to_tag(base_typeclass_info_const(M,C,_,N), _, _,
|
|
base_typeclass_info_constant(M,C,N)).
|
|
code_util__cons_id_to_tag(tabling_pointer_const(PredId,ProcId), _, _,
|
|
tabling_pointer_constant(PredId,ProcId)).
|
|
code_util__cons_id_to_tag(deep_profiling_proc_static(PPId), _, _,
|
|
deep_profiling_proc_static_tag(PPId)).
|
|
code_util__cons_id_to_tag(cons(Name, Arity), Type, ModuleInfo, Tag) :-
|
|
(
|
|
% handle the `character' type specially
|
|
Type = term__functor(term__atom("character"), [], _),
|
|
Name = unqualified(ConsName),
|
|
string__char_to_string(Char, ConsName)
|
|
->
|
|
char__to_int(Char, CharCode),
|
|
Tag = int_constant(CharCode)
|
|
;
|
|
% Tuples do not need a tag. Note that unary tuples are not
|
|
% treated as no_tag types. There's no reason why they
|
|
% couldn't be, it's just not worth the effort.
|
|
type_is_tuple(Type, _)
|
|
->
|
|
Tag = unshared_tag(0)
|
|
;
|
|
% Use the type to determine the type_id
|
|
( type_to_type_id(Type, TypeId0, _) ->
|
|
TypeId = TypeId0
|
|
;
|
|
% the type-checker should ensure that this never happens
|
|
error("code_util__cons_id_to_tag: invalid type")
|
|
),
|
|
|
|
% Given the type_id, lookup up the constructor tag
|
|
% table for that type
|
|
module_info_types(ModuleInfo, TypeTable),
|
|
map__lookup(TypeTable, TypeId, TypeDefn),
|
|
hlds_data__get_type_defn_body(TypeDefn, TypeBody),
|
|
(
|
|
TypeBody = du_type(_, ConsTable0, _, _)
|
|
->
|
|
ConsTable = ConsTable0
|
|
;
|
|
% this should never happen
|
|
error(
|
|
"code_util__cons_id_to_tag: type is not d.u. type?"
|
|
)
|
|
),
|
|
% Finally look up the cons_id in the table
|
|
map__lookup(ConsTable, cons(Name, Arity), Tag)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
code_util__cannot_stack_flush(GoalExpr - _) :-
|
|
code_util__cannot_stack_flush_2(GoalExpr).
|
|
|
|
:- pred code_util__cannot_stack_flush_2(hlds_goal_expr).
|
|
:- mode code_util__cannot_stack_flush_2(in) is semidet.
|
|
|
|
code_util__cannot_stack_flush_2(unify(_, _, _, Unify, _)) :-
|
|
Unify \= complicated_unify(_, _, _).
|
|
code_util__cannot_stack_flush_2(call(_, _, _, BuiltinState, _, _)) :-
|
|
BuiltinState = inline_builtin.
|
|
code_util__cannot_stack_flush_2(conj(Goals)) :-
|
|
code_util__cannot_stack_flush_goals(Goals).
|
|
code_util__cannot_stack_flush_2(switch(_, _, Cases, _)) :-
|
|
code_util__cannot_stack_flush_cases(Cases).
|
|
|
|
:- pred code_util__cannot_stack_flush_goals(list(hlds_goal)).
|
|
:- mode code_util__cannot_stack_flush_goals(in) is semidet.
|
|
|
|
code_util__cannot_stack_flush_goals([]).
|
|
code_util__cannot_stack_flush_goals([Goal | Goals]) :-
|
|
code_util__cannot_stack_flush(Goal),
|
|
code_util__cannot_stack_flush_goals(Goals).
|
|
|
|
:- pred code_util__cannot_stack_flush_cases(list(case)).
|
|
:- mode code_util__cannot_stack_flush_cases(in) is semidet.
|
|
|
|
code_util__cannot_stack_flush_cases([]).
|
|
code_util__cannot_stack_flush_cases([case(_, Goal) | Cases]) :-
|
|
code_util__cannot_stack_flush(Goal),
|
|
code_util__cannot_stack_flush_cases(Cases).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
code_util__cannot_fail_before_stack_flush(GoalExpr - GoalInfo) :-
|
|
goal_info_get_determinism(GoalInfo, Detism),
|
|
determinism_components(Detism, CanFail, _),
|
|
( CanFail = cannot_fail ->
|
|
true
|
|
;
|
|
code_util__cannot_fail_before_stack_flush_2(GoalExpr)
|
|
).
|
|
|
|
:- pred code_util__cannot_fail_before_stack_flush_2(hlds_goal_expr).
|
|
:- mode code_util__cannot_fail_before_stack_flush_2(in) is semidet.
|
|
|
|
code_util__cannot_fail_before_stack_flush_2(conj(Goals)) :-
|
|
code_util__cannot_fail_before_stack_flush_conj(Goals).
|
|
|
|
:- pred code_util__cannot_fail_before_stack_flush_conj(list(hlds_goal)).
|
|
:- mode code_util__cannot_fail_before_stack_flush_conj(in) is semidet.
|
|
|
|
code_util__cannot_fail_before_stack_flush_conj([]).
|
|
code_util__cannot_fail_before_stack_flush_conj([Goal | Goals]) :-
|
|
Goal = GoalExpr - GoalInfo,
|
|
(
|
|
(
|
|
GoalExpr = call(_, _, _, BuiltinState, _, _),
|
|
BuiltinState \= inline_builtin
|
|
;
|
|
GoalExpr = generic_call(_, _, _, _)
|
|
)
|
|
->
|
|
true
|
|
;
|
|
goal_info_get_determinism(GoalInfo, Detism),
|
|
determinism_components(Detism, cannot_fail, _)
|
|
->
|
|
code_util__cannot_fail_before_stack_flush_conj(Goals)
|
|
;
|
|
fail
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
code_util__count_recursive_calls(Goal - _, PredId, ProcId, Min, Max) :-
|
|
code_util__count_recursive_calls_2(Goal, PredId, ProcId, Min, Max).
|
|
|
|
:- pred code_util__count_recursive_calls_2(hlds_goal_expr, pred_id, proc_id,
|
|
int, int).
|
|
:- mode code_util__count_recursive_calls_2(in, in, in, out, out) is det.
|
|
|
|
code_util__count_recursive_calls_2(not(Goal), PredId, ProcId, Min, Max) :-
|
|
code_util__count_recursive_calls(Goal, PredId, ProcId, Min, Max).
|
|
code_util__count_recursive_calls_2(some(_, _, Goal),
|
|
PredId, ProcId, Min, Max) :-
|
|
code_util__count_recursive_calls(Goal, PredId, ProcId, Min, Max).
|
|
code_util__count_recursive_calls_2(unify(_, _, _, _, _), _, _, 0, 0).
|
|
code_util__count_recursive_calls_2(generic_call(_, _, _, _), _, _,
|
|
0, 0).
|
|
code_util__count_recursive_calls_2(foreign_proc(_, _, _, _, _, _, _),
|
|
_, _, 0, 0).
|
|
code_util__count_recursive_calls_2(call(CallPredId, CallProcId, _, _, _, _),
|
|
PredId, ProcId, Count, Count) :-
|
|
(
|
|
PredId = CallPredId,
|
|
ProcId = CallProcId
|
|
->
|
|
Count = 1
|
|
;
|
|
Count = 0
|
|
).
|
|
code_util__count_recursive_calls_2(conj(Goals), PredId, ProcId, Min, Max) :-
|
|
code_util__count_recursive_calls_conj(Goals, PredId, ProcId, 0, 0,
|
|
Min, Max).
|
|
code_util__count_recursive_calls_2(par_conj(Goals, _), PredId, ProcId, Min, Max) :-
|
|
code_util__count_recursive_calls_conj(Goals, PredId, ProcId, 0, 0, Min, Max).
|
|
code_util__count_recursive_calls_2(disj(Goals, _), PredId, ProcId, Min, Max) :-
|
|
code_util__count_recursive_calls_disj(Goals, PredId, ProcId, Min, Max).
|
|
code_util__count_recursive_calls_2(switch(_, _, Cases, _), PredId, ProcId,
|
|
Min, Max) :-
|
|
code_util__count_recursive_calls_cases(Cases, PredId, ProcId, Min, Max).
|
|
code_util__count_recursive_calls_2(if_then_else(_, Cond, Then, Else, _),
|
|
PredId, ProcId, Min, Max) :-
|
|
code_util__count_recursive_calls(Cond, PredId, ProcId, CMin, CMax),
|
|
code_util__count_recursive_calls(Then, PredId, ProcId, TMin, TMax),
|
|
code_util__count_recursive_calls(Else, PredId, ProcId, EMin, EMax),
|
|
CTMin is CMin + TMin,
|
|
CTMax is CMax + TMax,
|
|
int__min(CTMin, EMin, Min),
|
|
int__max(CTMax, EMax, Max).
|
|
code_util__count_recursive_calls_2(shorthand(_),
|
|
_, _, _, _) :-
|
|
% these should have been expanded out by now
|
|
error("code_util__count_recursive_calls_2: unexpected shorthand").
|
|
|
|
:- pred code_util__count_recursive_calls_conj(list(hlds_goal),
|
|
pred_id, proc_id, int, int, int, int).
|
|
:- mode code_util__count_recursive_calls_conj(in, in, in, in, in, out, out)
|
|
is det.
|
|
|
|
code_util__count_recursive_calls_conj([], _, _, Min, Max, Min, Max).
|
|
code_util__count_recursive_calls_conj([Goal | Goals], PredId, ProcId,
|
|
Min0, Max0, Min, Max) :-
|
|
code_util__count_recursive_calls(Goal, PredId, ProcId, Min1, Max1),
|
|
Min2 is Min0 + Min1,
|
|
Max2 is Max0 + Max1,
|
|
code_util__count_recursive_calls_conj(Goals, PredId, ProcId,
|
|
Min2, Max2, Min, Max).
|
|
|
|
:- pred code_util__count_recursive_calls_disj(list(hlds_goal),
|
|
pred_id, proc_id, int, int).
|
|
:- mode code_util__count_recursive_calls_disj(in, in, in, out, out) is det.
|
|
|
|
code_util__count_recursive_calls_disj([], _, _, 0, 0).
|
|
code_util__count_recursive_calls_disj([Goal | Goals], PredId, ProcId,
|
|
Min, Max) :-
|
|
( Goals = [] ->
|
|
code_util__count_recursive_calls(Goal, PredId, ProcId,
|
|
Min, Max)
|
|
;
|
|
code_util__count_recursive_calls(Goal, PredId, ProcId,
|
|
Min0, Max0),
|
|
code_util__count_recursive_calls_disj(Goals, PredId, ProcId,
|
|
Min1, Max1),
|
|
int__min(Min0, Min1, Min),
|
|
int__max(Max0, Max1, Max)
|
|
).
|
|
|
|
:- pred code_util__count_recursive_calls_cases(list(case),
|
|
pred_id, proc_id, int, int).
|
|
:- mode code_util__count_recursive_calls_cases(in, in, in, out, out) is det.
|
|
|
|
code_util__count_recursive_calls_cases([], _, _, _, _) :-
|
|
error("empty cases in code_util__count_recursive_calls_cases").
|
|
code_util__count_recursive_calls_cases([case(_, Goal) | Cases], PredId, ProcId,
|
|
Min, Max) :-
|
|
( Cases = [] ->
|
|
code_util__count_recursive_calls(Goal, PredId, ProcId,
|
|
Min, Max)
|
|
;
|
|
code_util__count_recursive_calls(Goal, PredId, ProcId,
|
|
Min0, Max0),
|
|
code_util__count_recursive_calls_cases(Cases, PredId, ProcId,
|
|
Min1, Max1),
|
|
int__min(Min0, Min1, Min),
|
|
int__max(Max0, Max1, Max)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
code_util__lvals_in_lvals([], []).
|
|
code_util__lvals_in_lvals([First | Rest], Lvals) :-
|
|
code_util__lvals_in_lval(First, FirstLvals),
|
|
code_util__lvals_in_lvals(Rest, RestLvals),
|
|
list__append(FirstLvals, RestLvals, Lvals).
|
|
|
|
code_util__lvals_in_rval(lval(Lval), [Lval | Lvals]) :-
|
|
code_util__lvals_in_lval(Lval, Lvals).
|
|
code_util__lvals_in_rval(var(_), []).
|
|
code_util__lvals_in_rval(create(_, _, _, _, _, _, _), []).
|
|
code_util__lvals_in_rval(mkword(_, Rval), Lvals) :-
|
|
code_util__lvals_in_rval(Rval, Lvals).
|
|
code_util__lvals_in_rval(const(_), []).
|
|
code_util__lvals_in_rval(unop(_, Rval), Lvals) :-
|
|
code_util__lvals_in_rval(Rval, Lvals).
|
|
code_util__lvals_in_rval(binop(_, Rval1, Rval2), Lvals) :-
|
|
code_util__lvals_in_rval(Rval1, Lvals1),
|
|
code_util__lvals_in_rval(Rval2, Lvals2),
|
|
list__append(Lvals1, Lvals2, Lvals).
|
|
code_util__lvals_in_rval(mem_addr(MemRef), Lvals) :-
|
|
code_util__lvals_in_mem_ref(MemRef, Lvals).
|
|
|
|
code_util__lvals_in_lval(reg(_, _), []).
|
|
code_util__lvals_in_lval(stackvar(_), []).
|
|
code_util__lvals_in_lval(framevar(_), []).
|
|
code_util__lvals_in_lval(succip, []).
|
|
code_util__lvals_in_lval(maxfr, []).
|
|
code_util__lvals_in_lval(curfr, []).
|
|
code_util__lvals_in_lval(succip(Rval), Lvals) :-
|
|
code_util__lvals_in_rval(Rval, Lvals).
|
|
code_util__lvals_in_lval(redofr(Rval), Lvals) :-
|
|
code_util__lvals_in_rval(Rval, Lvals).
|
|
code_util__lvals_in_lval(redoip(Rval), Lvals) :-
|
|
code_util__lvals_in_rval(Rval, Lvals).
|
|
code_util__lvals_in_lval(succfr(Rval), Lvals) :-
|
|
code_util__lvals_in_rval(Rval, Lvals).
|
|
code_util__lvals_in_lval(prevfr(Rval), Lvals) :-
|
|
code_util__lvals_in_rval(Rval, Lvals).
|
|
code_util__lvals_in_lval(hp, []).
|
|
code_util__lvals_in_lval(sp, []).
|
|
code_util__lvals_in_lval(field(_, Rval1, Rval2), Lvals) :-
|
|
code_util__lvals_in_rval(Rval1, Lvals1),
|
|
code_util__lvals_in_rval(Rval2, Lvals2),
|
|
list__append(Lvals1, Lvals2, Lvals).
|
|
code_util__lvals_in_lval(lvar(_), []).
|
|
code_util__lvals_in_lval(temp(_, _), []).
|
|
code_util__lvals_in_lval(mem_ref(Rval), Lvals) :-
|
|
code_util__lvals_in_rval(Rval, Lvals).
|
|
|
|
:- pred code_util__lvals_in_mem_ref(mem_ref, list(lval)).
|
|
:- mode code_util__lvals_in_mem_ref(in, out) is det.
|
|
|
|
code_util__lvals_in_mem_ref(stackvar_ref(_), []).
|
|
code_util__lvals_in_mem_ref(framevar_ref(_), []).
|
|
code_util__lvals_in_mem_ref(heap_ref(Rval, _, _), Lvals) :-
|
|
code_util__lvals_in_rval(Rval, Lvals).
|
|
|
|
%-----------------------------------------------------------------------------%
|