Files
mercury/compiler/trace_params.m
Julien Fischer 459847a064 Move the univ, maybe, pair and unit types from std_util into their own
Estimated hours taken: 18
Branches: main

Move the univ, maybe, pair and unit types from std_util into their own
modules.  std_util still contains the general purpose higher-order programming
constructs.

library/std_util.m:
	Move univ, maybe, pair and unit (plus any other related types
	and procedures) into their own modules.

library/maybe.m:
	New module.  This contains the maybe and maybe_error types and
	the associated procedures.

library/pair.m:
	New module.  This contains the pair type and associated procedures.

library/unit.m:
	New module. This contains the types unit/0 and unit/1.

library/univ.m:
	New module. This contains the univ type and associated procedures.

library/library.m:
	Add the new modules.

library/private_builtin.m:
	Update the declaration of the type_ctor_info struct for univ.

runtime/mercury.h:
	Update the declaration for the type_ctor_info struct for univ.

runtime/mercury_mcpp.h:
runtime/mercury_hlc_types.h:
	Update the definition of MR_Univ.

runtime/mercury_init.h:
	Fix a comment: ML_type_name is now exported from type_desc.m.

compiler/mlds_to_il.m:
	Update the the name of the module that defines univs (which are
	handled specially by the il code generator.)

library/*.m:
compiler/*.m:
browser/*.m:
mdbcomp/*.m:
profiler/*.m:
deep_profiler/*.m:
	Conform to the above changes.  Import the new modules where they
	are needed; don't import std_util where it isn't needed.

	Fix formatting in lots of modules.  Delete duplicate module
	imports.

tests/*:
	Update the test suite to confrom to the above changes.
2006-03-29 08:09:58 +00:00

505 lines
19 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 2000-2006 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: trace_params.m.
% Author: zs.
% This module defines the parameters of execution tracing at various trace
% levels and with various settings of the --suppress-trace option.
%
% In most cases the trace level we want to apply to a procedure (which is its
% effective trace level) is the same as the global trace level. However, if the
% global trace level is shallow, then we optimize the handling of procedures
% that cannot be called from deep traced contexts. If a procedure is neither
% exported nor has its address taken, then it can only be called from other
% procedures in its module. If the module is shallow traced, this guarantees
% that we will never get any events from the procedure, so there is no point
% in including any tracing code in it in the first place. We therefore make
% its effective trace level "none" for must purposes (the purposes whose
% functions test effective trace levels). Apart from avoiding the overhead
% of calls to MR_trace, this also allows the code generator to preserve tail
% recursion optimization. However, we continue to generate the data structures
% that enable the debugger to walk the stack for such procedures. We accomplish
% this by making the relevant test work on the global trace level, not
% effective trace levels. Most of the other functions defined in this module
% convert the given (global) trace level into the effective trace level of
% the relevant procedure before calculating their result.
%-----------------------------------------------------------------------------%
:- module libs.trace_params.
:- interface.
:- import_module hlds.
:- import_module hlds.hlds_pred.
:- import_module mdbcomp.prim_data.
:- import_module bool.
:- import_module maybe.
%-----------------------------------------------------------------------------%
:- type trace_level.
:- type trace_suppress_items.
% The string should be the value of the --trace-level option;
% two bools should be the values of the `--require-tracing' and
% `--decl-debug' grade options.
%
% If the string is an acceptable trace level in the specified kinds of
% grades, return yes wrapper around the trace level.
%
% If the string is an known trace level that happens not to be
% acceptable in the specified kinds of grades, return no.
%
% If the string is not known trace level, fail.
%
:- pred convert_trace_level(string::in, bool::in, bool::in,
maybe(trace_level)::out) is semidet.
:- pred convert_trace_suppress(string::in, trace_suppress_items::out)
is semidet.
:- func default_trace_suppress = trace_suppress_items.
% These functions check for various properties of the global trace level.
%
:- func given_trace_level_is_none(trace_level) = bool.
:- func trace_level_allows_delay_death(trace_level) = bool.
:- func trace_needs_return_info(trace_level, trace_suppress_items) = bool.
% Should optimization passes maintain meaningful variable names
% where possible.
%
:- func trace_level_needs_meaningful_var_names(trace_level) = bool.
% These functions check for various properties of the given procedure's
% effective trace level.
%
:- func eff_trace_level_is_none(pred_info, proc_info, trace_level) = bool.
:- func eff_trace_level_needs_input_vars(pred_info, proc_info, trace_level)
= bool.
:- func eff_trace_level_needs_fixed_slots(pred_info, proc_info, trace_level)
= bool.
:- func eff_trace_level_needs_from_full_slot(pred_info, proc_info, trace_level)
= bool.
:- func eff_trace_needs_all_var_names(pred_info, proc_info, trace_level,
trace_suppress_items) = bool.
:- func eff_trace_needs_proc_body_reps(pred_info, proc_info, trace_level,
trace_suppress_items) = bool.
:- func eff_trace_needs_port(pred_info, proc_info, trace_level,
trace_suppress_items, trace_port) = bool.
:- func eff_trace_level(pred_info, proc_info, trace_level) = trace_level.
:- func trace_level_none = trace_level.
% Given a trace level for a module, return the trace level we should
% use for compiler-generated unify, index and compare predicates.
%
:- func trace_level_for_unify_compare(trace_level) = trace_level.
% This is used to represent the trace level in the module layout
% and in proc layouts.
%
:- func trace_level_rep(trace_level) = string.
:- func encode_suppressed_events(trace_suppress_items) = int.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module hlds.special_pred.
:- import_module mdbcomp.
:- import_module mdbcomp.prim_data.
:- import_module char.
:- import_module int.
:- import_module list.
:- import_module pair.
:- import_module set.
:- import_module string.
%-----------------------------------------------------------------------------%
:- type trace_level
---> none
; shallow
; deep
; decl_rep.
:- type trace_suppress_item
---> port(trace_port)
; return_info
; all_var_names
; proc_body_reps.
:- type trace_suppress_items == set(trace_suppress_item).
trace_level_none = none.
trace_level_for_unify_compare(none) = none.
trace_level_for_unify_compare(shallow) = shallow.
trace_level_for_unify_compare(deep) = shallow.
trace_level_for_unify_compare(decl_rep) = shallow.
convert_trace_level("minimum", no, no, yes(none)).
convert_trace_level("minimum", yes, no, yes(shallow)).
convert_trace_level("minimum", _, yes, yes(decl_rep)).
convert_trace_level("shallow", _, no, yes(shallow)).
convert_trace_level("shallow", _, yes, no).
convert_trace_level("deep", _, no, yes(deep)).
convert_trace_level("deep", _, yes, no).
convert_trace_level("decl", _, _, yes(decl_rep)).
convert_trace_level("rep", _, _, yes(decl_rep)).
convert_trace_level("default", no, no, yes(none)).
convert_trace_level("default", yes, no, yes(deep)).
convert_trace_level("default", _, yes, yes(decl_rep)).
eff_trace_level(PredInfo, ProcInfo, TraceLevel) = EffTraceLevel :-
( TraceLevel = none ->
EffTraceLevel = none
;
pred_info_get_origin(PredInfo, Origin),
( Origin = special_pred(SpecialPred - _) ->
% Unify and compare predicates can be called from the generic
% unify and compare predicates in builtin.m, so they can be called
% from outside this module even if they don't have their address
% taken.
%
% Index predicates can never be called from anywhere except
% the compare predicate.
%
% Initialise predicates invoke user-provided code. Whether that
% code has debugging enabled or not, there is no point in
% generating events in the initialise predicate itself.
(
SpecialPred = spec_pred_unify,
EffTraceLevel = shallow
;
SpecialPred = spec_pred_compare,
EffTraceLevel = shallow
;
SpecialPred = spec_pred_index,
EffTraceLevel = none
;
SpecialPred = spec_pred_init,
EffTraceLevel = TraceLevel
)
; Origin = created(io_tabling) ->
% Predicates called by a predicate that is I/O tabled should not be
% traced. If such a predicate were allowed to generate events then
% the event numbers of events after the I/O primitive would be
% different between the first and subsequent (idempotent)
% executions of the same I/O action.
EffTraceLevel = none
;
pred_info_get_import_status(PredInfo, Status),
(
TraceLevel = shallow,
status_is_exported(Status, no),
proc_info_get_is_address_taken(ProcInfo, address_is_not_taken)
->
EffTraceLevel = none
;
EffTraceLevel = TraceLevel
)
)
).
given_trace_level_is_none(TraceLevel) =
trace_level_is_none(TraceLevel).
eff_trace_level_is_none(PredInfo, ProcInfo, TraceLevel) =
trace_level_is_none(eff_trace_level(PredInfo, ProcInfo, TraceLevel)).
eff_trace_level_needs_input_vars(PredInfo, ProcInfo, TraceLevel) =
trace_level_needs_input_vars(
eff_trace_level(PredInfo, ProcInfo, TraceLevel)).
eff_trace_level_needs_fixed_slots(PredInfo, ProcInfo, TraceLevel) =
trace_level_needs_fixed_slots(
eff_trace_level(PredInfo, ProcInfo, TraceLevel)).
eff_trace_level_needs_from_full_slot(PredInfo, ProcInfo, TraceLevel) =
trace_level_needs_from_full_slot(
eff_trace_level(PredInfo, ProcInfo, TraceLevel)).
eff_trace_needs_all_var_names(PredInfo, ProcInfo, TraceLevel, SuppressItems) =
trace_needs_all_var_names(eff_trace_level(PredInfo, ProcInfo, TraceLevel),
SuppressItems).
eff_trace_needs_proc_body_reps(PredInfo, ProcInfo, TraceLevel, SuppressItems) =
trace_needs_proc_body_reps(eff_trace_level(PredInfo, ProcInfo, TraceLevel),
SuppressItems).
eff_trace_needs_port(PredInfo, ProcInfo, TraceLevel, SuppressItems, Port) =
trace_needs_port(eff_trace_level(PredInfo, ProcInfo, TraceLevel),
SuppressItems, Port).
:- func trace_level_is_none(trace_level) = bool.
:- func trace_level_needs_input_vars(trace_level) = bool.
:- func trace_level_needs_fixed_slots(trace_level) = bool.
:- func trace_level_needs_from_full_slot(trace_level) = bool.
:- func trace_needs_all_var_names(trace_level, trace_suppress_items) = bool.
:- func trace_needs_proc_body_reps(trace_level, trace_suppress_items) = bool.
:- func trace_needs_port(trace_level, trace_suppress_items, trace_port) = bool.
trace_level_is_none(none) = yes.
trace_level_is_none(shallow) = no.
trace_level_is_none(deep) = no.
trace_level_is_none(decl_rep) = no.
trace_level_needs_input_vars(none) = no.
trace_level_needs_input_vars(shallow) = yes.
trace_level_needs_input_vars(deep) = yes.
trace_level_needs_input_vars(decl_rep) = yes.
trace_level_needs_fixed_slots(none) = no.
trace_level_needs_fixed_slots(shallow) = yes.
trace_level_needs_fixed_slots(deep) = yes.
trace_level_needs_fixed_slots(decl_rep) = yes.
trace_level_needs_from_full_slot(none) = no.
trace_level_needs_from_full_slot(shallow) = yes.
trace_level_needs_from_full_slot(deep) = no.
trace_level_needs_from_full_slot(decl_rep) = no.
trace_level_allows_delay_death(none) = no.
trace_level_allows_delay_death(shallow) = no.
trace_level_allows_delay_death(deep) = yes.
trace_level_allows_delay_death(decl_rep) = yes.
trace_level_needs_meaningful_var_names(none) = no.
trace_level_needs_meaningful_var_names(shallow) = no.
trace_level_needs_meaningful_var_names(deep) = yes.
trace_level_needs_meaningful_var_names(decl_rep) = yes.
trace_needs_return_info(TraceLevel, TraceSuppressItems) = Need :-
(
trace_level_has_return_info(TraceLevel) = yes,
\+ set.member(return_info, TraceSuppressItems)
->
Need = yes
;
Need = no
).
trace_needs_all_var_names(TraceLevel, TraceSuppressItems) = Need :-
(
trace_level_has_all_var_names(TraceLevel) = yes,
\+ set.member(all_var_names, TraceSuppressItems)
->
Need = yes
;
Need = no
).
trace_needs_proc_body_reps(TraceLevel, TraceSuppressItems) = Need :-
(
trace_level_has_proc_body_reps(TraceLevel) = yes,
\+ set.member(proc_body_reps, TraceSuppressItems)
->
Need = yes
;
Need = no
).
:- func trace_level_has_return_info(trace_level) = bool.
:- func trace_level_has_all_var_names(trace_level) = bool.
:- func trace_level_has_proc_body_reps(trace_level) = bool.
trace_level_has_return_info(none) = no.
trace_level_has_return_info(shallow) = yes.
trace_level_has_return_info(deep) = yes.
trace_level_has_return_info(decl_rep) = yes.
trace_level_has_all_var_names(none) = no.
trace_level_has_all_var_names(shallow) = no.
trace_level_has_all_var_names(deep) = no.
trace_level_has_all_var_names(decl_rep) = yes.
trace_level_has_proc_body_reps(none) = no.
trace_level_has_proc_body_reps(shallow) = no.
trace_level_has_proc_body_reps(deep) = no.
trace_level_has_proc_body_reps(decl_rep) = yes.
convert_trace_suppress(SuppressString, SuppressItemSet) :-
SuppressWords = string.words(char_is_comma, SuppressString),
list.map(convert_item_name, SuppressWords, SuppressItemLists),
list.condense(SuppressItemLists, SuppressItems),
set.list_to_set(SuppressItems, SuppressItemSet).
:- pred char_is_comma(char::in) is semidet.
char_is_comma(',').
default_trace_suppress = set.init.
:- func convert_port_name(string) = trace_port is semidet.
% The call port cannot be disabled, because its layout structure is
% referred to implicitly by the redo command in mdb.
%
% The exception port cannot be disabled, because it is never put into
% compiler-generated code in the first place; such events are created
% on the fly by library/exception.m.
% convert_port_name("call") = call.
convert_port_name("exit") = exit.
convert_port_name("fail") = fail.
convert_port_name("redo") = redo.
% convert_port_name("excp") = exception.
convert_port_name("exception") = exception.
convert_port_name("cond") = ite_cond.
convert_port_name("ite_cond") = ite_cond.
convert_port_name("then") = ite_then.
convert_port_name("ite_then") = ite_then.
convert_port_name("else") = ite_else.
convert_port_name("ite_else") = ite_else.
convert_port_name("nege") = neg_enter.
convert_port_name("neg_enter") = neg_enter.
convert_port_name("negs") = neg_success.
convert_port_name("neg_success") = neg_success.
convert_port_name("negf") = neg_failure.
convert_port_name("neg_failure") = neg_failure.
convert_port_name("swtc") = switch.
convert_port_name("switch") = switch.
convert_port_name("disj") = disj.
convert_port_name("frst") = nondet_pragma_first.
convert_port_name("nondet_pragma_first") = nondet_pragma_first.
convert_port_name("latr") = nondet_pragma_first.
convert_port_name("nondet_pragma_later") = nondet_pragma_later.
:- func convert_port_class_name(string) = list(trace_port) is semidet.
convert_port_class_name("interface") =
[call, exit, redo, fail, exception].
convert_port_class_name("internal") =
[ite_then, ite_else, switch, disj].
convert_port_class_name("context") =
[ite_cond, neg_enter, neg_success, neg_failure].
:- func convert_other_name(string) = trace_suppress_item is semidet.
convert_other_name("return") = return_info.
convert_other_name("return_info") = return_info.
convert_other_name("names") = all_var_names.
convert_other_name("all_var_names") = all_var_names.
convert_other_name("bodies") = proc_body_reps.
convert_other_name("proc_body_reps") = proc_body_reps.
:- pred convert_item_name(string::in, list(trace_suppress_item)::out)
is semidet.
convert_item_name(String, Names) :-
( convert_port_name(String) = PortName ->
Names = [port(PortName)]
; convert_port_class_name(String) = PortNames ->
list.map(wrap_port, PortNames, Names)
; convert_other_name(String) = OtherName ->
Names = [OtherName]
;
fail
).
:- pred wrap_port(trace_port::in, trace_suppress_item::out) is det.
wrap_port(Port, port(Port)).
% If this is modified, then the corresponding code in
% runtime/mercury_stack_layout.h needs to be updated.
trace_level_rep(none) = "MR_TRACE_LEVEL_NONE".
trace_level_rep(shallow) = "MR_TRACE_LEVEL_SHALLOW".
trace_level_rep(deep) = "MR_TRACE_LEVEL_DEEP".
trace_level_rep(decl_rep) = "MR_TRACE_LEVEL_DECL_REP".
%-----------------------------------------------------------------------------%
:- type port_category
---> interface % The events that describe the interface of a procedure
% with its callers.
; internal % The events inside each procedure that were present
% in the initial procedural debugger.
; context. % The events inside each procedure that we added
% because the declarative debugger needs to know when
% (potentially) negated contexts start and end.
:- func trace_port_category(trace_port) = port_category.
trace_port_category(call) = interface.
trace_port_category(exit) = interface.
trace_port_category(fail) = interface.
trace_port_category(redo) = interface.
trace_port_category(exception) = interface.
trace_port_category(ite_cond) = context.
trace_port_category(ite_then) = internal.
trace_port_category(ite_else) = internal.
trace_port_category(neg_enter) = context.
trace_port_category(neg_success) = context.
trace_port_category(neg_failure) = context.
trace_port_category(switch) = internal.
trace_port_category(disj) = internal.
trace_port_category(nondet_pragma_first) = internal.
trace_port_category(nondet_pragma_later) = internal.
:- func trace_level_port_categories(trace_level) = list(port_category).
trace_level_port_categories(none) = [].
trace_level_port_categories(shallow) = [interface].
trace_level_port_categories(deep) = [interface, internal, context].
trace_level_port_categories(decl_rep) = [interface, internal, context].
:- func trace_level_allows_port_suppression(trace_level) = bool.
trace_level_allows_port_suppression(none) = no. % no ports exist
trace_level_allows_port_suppression(shallow) = yes.
trace_level_allows_port_suppression(deep) = yes.
trace_level_allows_port_suppression(decl_rep) = no.
trace_needs_port(TraceLevel, TraceSuppressItems, Port) = NeedsPort :-
(
trace_port_category(Port) = Category,
list.member(Category, trace_level_port_categories(TraceLevel)),
\+ (
trace_level_allows_port_suppression(TraceLevel) = yes,
set.member(port(Port), TraceSuppressItems)
)
->
NeedsPort = yes
;
NeedsPort = no
).
encode_suppressed_events(SuppressedEvents) = SuppressedEventsInt :-
set.fold(maybe_add_suppressed_event, SuppressedEvents,
0, SuppressedEventsInt).
:- pred maybe_add_suppressed_event(trace_suppress_item::in, int::in, int::out)
is det.
maybe_add_suppressed_event(SuppressItem, SuppressedEventsInt0,
SuppressedEventsInt) :-
( SuppressItem = port(Port) ->
SuppressedEventsInt = SuppressedEventsInt0 \/ (1 << port_number(Port))
;
SuppressedEventsInt = SuppressedEventsInt0
).
:- func port_number(trace_port) = int.
port_number(call) = 1.
port_number(exit) = 2.
port_number(redo) = 3.
port_number(fail) = 4.
port_number(exception) = 5.
port_number(ite_cond) = 6.
port_number(ite_then) = 7.
port_number(ite_else) = 8.
port_number(neg_enter) = 9.
port_number(neg_success) = 10.
port_number(neg_failure) = 11.
port_number(disj) = 12.
port_number(switch) = 13.
port_number(nondet_pragma_first) = 14.
port_number(nondet_pragma_later) = 15.