Files
mercury/grade_lib/grade_spec.m
Zoltan Somogyi 32006a1c7c Rename and generalize .c_debug to .target_debug.
runtime/mercury_grade.h:
    Rename the grade modifier, and the C macro that represents it.

compiler/options.m:
    Rename the --c-debug-grade option to --target-debug-grade.

compiler/compute_grade.m:
    Rename the grade modifier, and the option that represents it.

    Restrict the .target_debut grade modifier to MLDS grades.

compiler/handle_options.m:
    Implement --target-debug-grade by having it imply --target-debug.

compiler/compile_target_code.m:
compiler/link_target_code.m:
    Pay attention to either --target-debug-grade (for purposes related
    to the grade itself) and to --target-debug (for all other purposes).

scripts/canonical_grade.in:
scripts/canonical_grade.sh-subr:
scripts/final_grade_options.sh-subr:
scripts/init_grade_options.sh-subr:
scripts/parse_grade_options.sh-subr:
    Parse target_debug grade modifiers and --target-debug-grade options
    instead of c_debug grade modifiers and --c-debug-grade options.

    Add (normally commented-out) infrastructure to make it easier
    to debug changes.

    Restrict the .target_debut grade modifier to MLDS grades.

scripts/mgnuc.in:
scripts/mgnuc_file_opts.sh-subr:
    Rename some variables to clarify the distinction between the
    --target-debug option (which, like -g, enabled debugging of only one file)
    and the --target-debug-grade option (which enables it for the whole
    program).

configure.ac:
    Make it easier to debug grade-related changes by recording
    both autoconfigured and user-supplied grades that the rejected by
    the canonical_grade script.

    Conform to the changes above.

README.sanitizers:
doc/user_guide.texi:
grade_lib/grade_spec.m:
grade_lib/grade_string.m:
scripts/ml.in:
tests/warnings/help_text.err_exp:
tools/lmc.in:
tools/test_mercury:
    Conform to the changes above.

scripts/Mmake.vars.in:
    Add some XXXs about style.
2025-08-09 21:48:23 +02:00

961 lines
37 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ts=4 sw=4 et ft=mercury
%---------------------------------------------------------------------------%
% Copyright (C) 2016, 2018, 2020, 2022, 2025 The Mercury team.
% This file is distributed under the terms specified in COPYING.LIB.
%---------------------------------------------------------------------------%
%
% This module defines the "terrain" on which the grade solver operates,
% by defining the list of solver variables, the values they may have,
% and the constraints that assignments of values to solver variables
% must satisfy to be a valid solution.
%
% To keep this module easy to read and thus to check, it contains only
% specification-level information; it intentionally leaves out the data
% structures needed during constraint solving that are irrelevant to
% the specification of the problem. Those will be added by the code of
% setup_solver_info in grade_setup.m.
%
:- module grade_lib.grade_spec.
:- interface.
:- import_module list.
%---------------------------------------------------------------------------%
%
% The solver_var_id and solver_var_value_id types embody one of the four
% representations of grades described in compiler/notes/grade_library.html.
% This is the representation used by the solver, because it allows
% the solver to use generic code to implement propagation on *all*
% requirements, regardless of what solver variables and values they involve.
%
:- type solver_var_id
---> svar_ac_gcc_regs_avail
; svar_ac_gcc_gotos_avail
; svar_ac_gcc_labels_avail
; svar_ac_low_tag_bits_avail
; svar_ac_size_of_double
; svar_ac_merc_file
; svar_backend
; svar_target
; svar_gcc_conf
; svar_low_tag_bits_use
; svar_stack_len
; svar_trail
; svar_minmodel
; svar_thread_safe
; svar_gc
; svar_deep_prof
; svar_mprof_call
; svar_mprof_time
; svar_mprof_memory
; svar_tscope_prof
% Paul wants to call the threadscope style profiler a different
% name, since the data it generates isn't compatible with
% threadscope anymore. But the name we use here in the solver
% isn't visible outside, and "tscope" gives readers the right
% intuition.
; svar_term_size_prof
; svar_debug
; svar_ssdebug
; svar_target_debug
; svar_rbmm
; svar_rbmm_debug
; svar_rbmm_prof
; svar_pregen
; svar_request_single_prec_float
; svar_merc_float.
:- type solver_var_value_id
---> svalue_ac_gcc_regs_avail_no
; svalue_ac_gcc_regs_avail_yes
; svalue_ac_gcc_gotos_avail_no
; svalue_ac_gcc_gotos_avail_yes
; svalue_ac_gcc_labels_avail_no
; svalue_ac_gcc_labels_avail_yes
; svalue_ac_low_tag_bits_avail_0
; svalue_ac_low_tag_bits_avail_2
; svalue_ac_low_tag_bits_avail_3
% Autoconf can detect that 4 low tag bits are available.
% However, since we never use 4 low tag bits, this is functionally
% indistinguishable from 3 low tag bits being available,
% so we require the code setting up the grade settings to be solved
% to map 4 avail tag bits to 3.
; svalue_ac_size_of_double_eq_ptr
; svalue_ac_size_of_double_ne_ptr
; svalue_ac_merc_file_no
; svalue_ac_merc_file_yes
; svalue_backend_mlds
; svalue_backend_llds
; svalue_target_c
; svalue_target_csharp
; svalue_target_java
; svalue_gcc_conf_none % used for non-LLDS backends
; svalue_gcc_conf_reg
; svalue_gcc_conf_jump
; svalue_gcc_conf_fast
; svalue_gcc_conf_asm_jump
; svalue_gcc_conf_asm_fast
; svalue_low_tag_bits_use_0
% If we are using 0 low primary tag bits, then the data
% representation may use no primary tag at all.
% Once upon a time, we *could* use (an almost arbitrary number of)
% high primary tag bits, but we eventually removed that capability,
% never having used it for anything except benchmarking the extent
% of the superiority of low tags :-).
%
% If we ever wanted to bring back high tags, which is extremely
% unlikely, we would need a new solver variable named (say)
% svar_high_tag_bits_use, whose value being any nonzero value
% would imply svalue_low_tag_bits_use_0.
; svalue_low_tag_bits_use_2
; svalue_low_tag_bits_use_3
; svalue_stack_len_std
; svalue_stack_len_segments
; svalue_stack_len_extend
; svalue_trail_no
; svalue_trail_yes
; svalue_minmodel_no
; svalue_minmodel_stack_copy
; svalue_minmodel_stack_copy_debug
; svalue_minmodel_own_stack
; svalue_minmodel_own_stack_debug
; svalue_thread_safe_c_no
; svalue_thread_safe_c_yes
; svalue_thread_safe_target_native
; svalue_gc_none
; svalue_gc_bdw
; svalue_gc_bdw_debug
; svalue_gc_target_native
; svalue_gc_accurate
; svalue_gc_history
; svalue_deep_prof_no
; svalue_deep_prof_yes
; svalue_mprof_call_no
; svalue_mprof_call_yes
; svalue_mprof_time_no
; svalue_mprof_time_yes
; svalue_mprof_memory_no
; svalue_mprof_memory_yes
; svalue_tscope_prof_no
; svalue_tscope_prof_yes
; svalue_term_size_prof_no
; svalue_term_size_prof_cells
; svalue_term_size_prof_words
; svalue_debug_none
; svalue_debug_debug
; svalue_debug_decldebug
; svalue_ssdebug_no
; svalue_ssdebug_yes
; svalue_target_debug_no
; svalue_target_debug_yes
; svalue_rbmm_no
; svalue_rbmm_yes
; svalue_rbmm_debug_no
; svalue_rbmm_debug_yes
; svalue_rbmm_prof_no
; svalue_rbmm_prof_yes
; svalue_pregen_no
; svalue_pregen_yes
; svalue_request_single_prec_float_no
; svalue_request_single_prec_float_yes
; svalue_merc_float_is_boxed_c_double
; svalue_merc_float_is_unboxed_c_double
; svalue_merc_float_is_unboxed_c_float.
%---------------------------------------------------------------------------%
% See the documentation of init_solver_var_specs below.
:- type specs_version
---> specs_version_0
; specs_version_1.
% solvar_var_spec(VarId, [ValueId1, ValueId2, ... ValueIdN]) means that
% the value of VarId must be one of {ValueId1, ValueId2, ValueIdN}.
%
:- type solver_var_spec
---> solver_var_spec(
svs_var :: solver_var_id,
svs_values :: list(solver_var_value_id)
).
% Return the list of solver variables in a grade specification problem,
% and the list of possible values of each of those solver variables.
%
% The order of solver variables in the returned list is the order
% in which labeling will try to choose a variable to bind.
%
% The order of values within each solver variable is the order of
% preference: labeling will always choose to set the chosen solver variable
% to the first of its values that has not previously been ruled out.
%
% For a few solver variables, the order of "preference" we currently use
% is not the one we *want* to use. If a grade string does not explicitly
% specify the use of a specific gc algorithm, we currently assume that this
% implicitly specifies NOT using any garbage collector, and we likewise
% assume that the absence of a grade component (.stseg or .exts) that
% asks for a dynamically sized stack means that the user wants a fixed
% size stack. This is "version 0" of the preferences, and hence of
% the solver var specs. However, we want to change the defaults
% to the use of the Boehm collector and stack segments respectively,
% which is what version 1 of the preferences calls for.
%
:- func init_solver_var_specs(specs_version) = list(solver_var_spec).
%---------------------------------------------------------------------------%
%
% A requirement is an implication of the form
%
% (IfVar `being` IfValue)
% `implies_that`
% (ThenVar `is_one_of` [ThenValue1, ..., ThenValueN])
%
% The solver can use the implication to do propagation in both directions.
%
% Forward direction: if the solver knows that IfVar = IfValue, it will
% mark all values of ThenVar that are not among ThenValue1 .. ThenValueN
% as not possible.
%
% Reverse direction: if the solver knows that ThenVar cannot be
% any of the values in ThenValue1 .. ThenValueN, then it will record that
% IfVar = IfValue is not possible either.
%
:- type if_spec
---> being(solver_var_id, solver_var_value_id).
:- type then_spec
---> is_one_of(solver_var_id, list(solver_var_value_id)).
:- type implication_spec
---> implies_that(if_spec, then_spec).
% Besides the implication, each requirement also has an explanation,
% which is a short sentence describing the rationale for the implication.
:- type requirement_spec
---> requirement_spec(
rs_explanation :: string,
rs_implication :: implication_spec
).
% Return the list of requirements that represent the dependencies
% and incompatibilities between grade components, as represented
% by their solver vars.
%
:- func init_requirement_specs = list(requirement_spec).
%---------------------------------------------------------------------------%
:- implementation.
%---------------------------------------------------------------------------%
init_solver_var_specs(SpecsVersion) = Specs :-
(
SpecsVersion = specs_version_0,
StackLenPrefOrder =
[svalue_stack_len_std, svalue_stack_len_segments,
svalue_stack_len_extend],
GcPrefOrder =
[svalue_gc_none, svalue_gc_bdw, svalue_gc_target_native,
svalue_gc_bdw_debug, svalue_gc_accurate, svalue_gc_history]
;
SpecsVersion = specs_version_1,
StackLenPrefOrder =
[svalue_stack_len_segments, svalue_stack_len_std,
svalue_stack_len_extend],
GcPrefOrder =
[svalue_gc_bdw, svalue_gc_target_native, svalue_gc_bdw_debug,
svalue_gc_none, svalue_gc_accurate, svalue_gc_history]
),
Specs = [
% This first group of variables are set (by setup_solver_info)
% to autoconfigured values before constraint solving starts.
% By putting them at the start, the very first labeling step will
% skip over them; later labelling steps won't have to look at them.
solver_var_spec(svar_ac_gcc_regs_avail,
[svalue_ac_gcc_regs_avail_no,
svalue_ac_gcc_regs_avail_yes]),
solver_var_spec(svar_ac_gcc_gotos_avail,
[svalue_ac_gcc_gotos_avail_no,
svalue_ac_gcc_gotos_avail_yes]),
solver_var_spec(svar_ac_gcc_labels_avail,
[svalue_ac_gcc_labels_avail_no,
svalue_ac_gcc_labels_avail_yes]),
solver_var_spec(svar_ac_low_tag_bits_avail,
[svalue_ac_low_tag_bits_avail_0,
svalue_ac_low_tag_bits_avail_2,
svalue_ac_low_tag_bits_avail_3]),
solver_var_spec(svar_ac_size_of_double,
[svalue_ac_size_of_double_eq_ptr,
svalue_ac_size_of_double_ne_ptr]),
solver_var_spec(svar_ac_merc_file,
[svalue_ac_merc_file_no, svalue_ac_merc_file_yes]),
solver_var_spec(svar_backend,
[svalue_backend_mlds, svalue_backend_llds]),
solver_var_spec(svar_target,
[svalue_target_c, svalue_target_csharp, svalue_target_java]),
solver_var_spec(svar_gcc_conf,
% XXX The order of preference here is partially speed,
% partially how well the grade is tested.
[svalue_gcc_conf_asm_fast,
svalue_gcc_conf_reg,
svalue_gcc_conf_none,
svalue_gcc_conf_fast,
svalue_gcc_conf_jump,
svalue_gcc_conf_asm_jump]),
solver_var_spec(svar_pregen,
[svalue_pregen_no, svalue_pregen_yes]),
solver_var_spec(svar_low_tag_bits_use,
[svalue_low_tag_bits_use_3, svalue_low_tag_bits_use_2,
svalue_low_tag_bits_use_0]),
solver_var_spec(svar_stack_len,
StackLenPrefOrder),
solver_var_spec(svar_trail,
[svalue_trail_no, svalue_trail_yes]),
solver_var_spec(svar_minmodel,
[svalue_minmodel_no,
svalue_minmodel_stack_copy, svalue_minmodel_stack_copy_debug,
svalue_minmodel_own_stack, svalue_minmodel_own_stack_debug]),
solver_var_spec(svar_thread_safe,
[svalue_thread_safe_c_no, svalue_thread_safe_c_yes,
svalue_thread_safe_target_native]),
solver_var_spec(svar_gc,
GcPrefOrder),
solver_var_spec(svar_deep_prof,
[svalue_deep_prof_no, svalue_deep_prof_yes]),
solver_var_spec(svar_mprof_call,
[svalue_mprof_call_no, svalue_mprof_call_yes]),
solver_var_spec(svar_mprof_time,
[svalue_mprof_time_no, svalue_mprof_time_yes]),
solver_var_spec(svar_mprof_memory,
[svalue_mprof_memory_no, svalue_mprof_memory_yes]),
solver_var_spec(svar_tscope_prof,
[svalue_tscope_prof_no, svalue_tscope_prof_yes]),
solver_var_spec(svar_term_size_prof,
[svalue_term_size_prof_no,
svalue_term_size_prof_cells, svalue_term_size_prof_words]),
solver_var_spec(svar_debug,
[svalue_debug_none, svalue_debug_debug, svalue_debug_decldebug]),
solver_var_spec(svar_ssdebug,
[svalue_ssdebug_no, svalue_ssdebug_yes]),
solver_var_spec(svar_target_debug,
[svalue_target_debug_no, svalue_target_debug_yes]),
solver_var_spec(svar_rbmm,
[svalue_rbmm_no, svalue_rbmm_yes]),
solver_var_spec(svar_rbmm_debug,
[svalue_rbmm_debug_no, svalue_rbmm_debug_yes]),
solver_var_spec(svar_rbmm_prof,
[svalue_rbmm_prof_no, svalue_rbmm_prof_yes]),
solver_var_spec(svar_request_single_prec_float,
[svalue_request_single_prec_float_no,
svalue_request_single_prec_float_yes]),
solver_var_spec(svar_merc_float,
[svalue_merc_float_is_unboxed_c_double,
svalue_merc_float_is_boxed_c_double,
svalue_merc_float_is_unboxed_c_float])
].
%---------------------------------------------------------------------------%
init_requirement_specs = [
% Requirements of values of svar_ac_gcc_regs_avail.
% None. The value is set by configure.
% Requirements of values of svar_ac_gcc_gotos_avail.
% None. The value is set by configure.
% Requirements of values of svar_ac_gcc_labels_avail.
% None. The value is set by configure.
% Requirements of values of svar_ac_low_tag_bits_avail.
% None. The value is set by configure.
% Requirements of values of svar_ac_size_of_double.
% None. The value is set by configure.
% Requirements of values of svar_ac_merc_file.
% None. The value is set by configure.
% Requirements of values of svar_backend.
requirement_spec(
"Using the MLDS backend requires targeting C, C# or Java.",
(svar_backend `being` svalue_backend_mlds) `implies_that`
(svar_target `is_one_of`
[svalue_target_c, svalue_target_csharp, svalue_target_java])
),
requirement_spec(
"Using the LLDS backend requires targeting C.",
(svar_backend `being` svalue_backend_llds) `implies_that`
(svar_target `is_one_of` [svalue_target_c])
),
requirement_spec(
"The .target_debug grade modifier requires the MLDS backend.",
% For LLDS grades that use gcc extensions to execute gotos
% between modules without going through function prologues/epilogues,
% using e.g. gdb is not going to be remotely useful.
% And for the LLDS grades that do *not* use such extensions,
% our use of threaded code will by very confusing for most anyone
% who is not a Mercury implementor.
(svar_backend `being` svalue_backend_llds) `implies_that`
(svar_target_debug `is_one_of` [svalue_target_debug_no])
),
requirement_spec(
"The use of gcc extensions makes sense only for the LLDS backend.",
(svar_backend `being` svalue_backend_mlds) `implies_that`
(svar_gcc_conf `is_one_of` [svalue_gcc_conf_none])
),
% Requirements of values of svar_target.
requirement_spec(
"Targeting C# requires the MLDS backend.",
(svar_target `being` svalue_target_csharp) `implies_that`
(svar_backend `is_one_of` [svalue_backend_mlds])
),
requirement_spec(
"Targeting Java requires the MLDS backend.",
(svar_target `being` svalue_target_java) `implies_that`
(svar_backend `is_one_of` [svalue_backend_mlds])
),
requirement_spec(
"C does not have a native garbage collector.",
(svar_target `being` svalue_target_c) `implies_that`
(svar_gc `is_one_of` [svalue_gc_bdw, svalue_gc_bdw_debug,
svalue_gc_accurate, svalue_gc_history, svalue_gc_none])
),
requirement_spec(
"Targeting C# requires target native gc.",
(svar_target `being` svalue_target_csharp) `implies_that`
(svar_gc `is_one_of` [svalue_gc_target_native])
),
requirement_spec(
"Targeting Java requires target native gc.",
(svar_target `being` svalue_target_java) `implies_that`
(svar_gc `is_one_of` [svalue_gc_target_native])
),
requirement_spec(
"C does not have its own native threading model.",
(svar_target `being` svalue_target_c) `implies_that`
(svar_thread_safe `is_one_of`
[svalue_thread_safe_c_no, svalue_thread_safe_c_yes])
),
requirement_spec(
"Generating C# implies using the C# threading model.",
(svar_target `being` svalue_target_csharp) `implies_that`
(svar_thread_safe `is_one_of` [svalue_thread_safe_target_native])
),
requirement_spec(
"Generating Java implies using the Java threading model.",
(svar_target `being` svalue_target_java) `implies_that`
(svar_thread_safe `is_one_of` [svalue_thread_safe_target_native])
),
% These are covered by a single requirement from spf back to target.
% requirement_spec(
% "Targeting C# is incompatible with single-precision floats.",
% (svar_target `being` svalue_target_csharp) `implies_that`
% (svar_single_prec_float `is_one_of` [svalue_single_prec_float_no])
% ),
% requirement_spec(
% "Targeting Java is incompatible with single-precision floats.",
% (svar_target `being` svalue_target_java) `implies_that`
% (svar_single_prec_float `is_one_of` [svalue_single_prec_float_no])
% ),
% Requirements of values of svar_gcc_conf.
% These requirements are expressed in reverse.
requirement_spec(
"Using gcc register extensions requires them to be available.",
(svar_ac_gcc_regs_avail `being` svalue_ac_gcc_regs_avail_no)
`implies_that`
(svar_gcc_conf `is_one_of`
[svalue_gcc_conf_none,
svalue_gcc_conf_jump,
svalue_gcc_conf_asm_jump])
),
requirement_spec(
"Using gcc nonlocal gotos requires them to be available.",
(svar_ac_gcc_gotos_avail `being` svalue_ac_gcc_gotos_avail_no)
`implies_that`
(svar_gcc_conf `is_one_of`
[svalue_gcc_conf_none,
svalue_gcc_conf_reg])
),
requirement_spec(
"Using gcc asm labels requires them to be available.",
(svar_ac_gcc_labels_avail `being` svalue_ac_gcc_labels_avail_no)
`implies_that`
(svar_gcc_conf `is_one_of`
[svalue_gcc_conf_none,
svalue_gcc_conf_reg,
svalue_gcc_conf_jump,
svalue_gcc_conf_fast])
),
% Requirements of values of svar_pregen.
requirement_spec(
"Pregenerated code always targets C.",
(svar_pregen `being` svalue_pregen_yes) `implies_that`
(svar_target `is_one_of` [svalue_target_c])
),
requirement_spec(
"Pregenerated code always uses none, reg, asm_fast or hlc.",
(svar_pregen `being` svalue_pregen_yes) `implies_that`
(svar_gcc_conf `is_one_of`
[svalue_gcc_conf_none, svalue_gcc_conf_reg,
svalue_gcc_conf_asm_fast])
),
requirement_spec(
"Pregenerated code uses 2 low tag bits.",
(svar_pregen `being` svalue_pregen_yes) `implies_that`
(svar_low_tag_bits_use `is_one_of` [svalue_low_tag_bits_use_2])
),
% XXX We should require stack segments on llds.
% With version 1 of the requirements, we prefer stack segments when
% possible, and with the llds backend, they are possible,
% but this is not as good as a requirement, since it can be overridden.
% Unfortunately, we don't (yet) support implications with *two*
% conditions, such as "pregen=yes and backend=llds implies stack segments".
% XXX Should we relax the following restriction?
requirement_spec(
"Pregenerated code never uses a trail.",
(svar_pregen `being` svalue_pregen_yes) `implies_that`
(svar_trail `is_one_of` [svalue_trail_no])
),
requirement_spec(
"Pregenerated code never uses minimal model.",
(svar_pregen `being` svalue_pregen_yes) `implies_that`
(svar_minmodel `is_one_of` [svalue_minmodel_no])
),
requirement_spec(
"Pregenerated code never supports thread safety.",
(svar_pregen `being` svalue_pregen_yes) `implies_that`
(svar_thread_safe `is_one_of` [svalue_thread_safe_c_no])
),
requirement_spec(
"Pregenerated code always uses the Boehm garbage collector.",
(svar_pregen `being` svalue_pregen_yes) `implies_that`
(svar_gc `is_one_of` [svalue_gc_bdw])
),
requirement_spec(
"Pregenerated code never supports deep profiling.",
(svar_pregen `being` svalue_pregen_yes) `implies_that`
(svar_deep_prof `is_one_of` [svalue_deep_prof_no])
),
requirement_spec(
"Pregenerated code never supports mprof-style profiling.",
(svar_pregen `being` svalue_pregen_yes) `implies_that`
(svar_mprof_call `is_one_of` [svalue_mprof_call_no])
),
requirement_spec(
"Pregenerated code never supports term size profiling.",
(svar_pregen `being` svalue_pregen_yes) `implies_that`
(svar_term_size_prof `is_one_of` [svalue_term_size_prof_no])
),
requirement_spec(
"Pregenerated code never supports debugging.",
(svar_pregen `being` svalue_pregen_yes) `implies_that`
(svar_debug `is_one_of` [svalue_debug_none])
),
requirement_spec(
"Pregenerated code never supports source-to-source debugging.",
(svar_pregen `being` svalue_pregen_yes) `implies_that`
(svar_ssdebug `is_one_of` [svalue_ssdebug_no])
),
requirement_spec(
"Pregenerated code never supports target language debugging.",
(svar_pregen `being` svalue_pregen_yes) `implies_that`
(svar_target_debug `is_one_of` [svalue_target_debug_no])
),
requirement_spec(
"Pregenerated code never supports region based memory management.",
(svar_pregen `being` svalue_pregen_yes) `implies_that`
(svar_rbmm `is_one_of` [svalue_rbmm_no])
),
requirement_spec(
"Pregenerated code always uses boxed double-precision floats.",
(svar_pregen `being` svalue_pregen_yes) `implies_that`
(svar_merc_float `is_one_of` [svalue_merc_float_is_boxed_c_double])
),
% Requirements of values of svar_low_tag_bits_use.
requirement_spec(
"Using 2 low tag bits needs at least 2 low tag bits to be available.",
(svar_low_tag_bits_use `being` svalue_low_tag_bits_use_2)
`implies_that`
(svar_ac_low_tag_bits_avail `is_one_of`
[svalue_ac_low_tag_bits_avail_2, svalue_ac_low_tag_bits_avail_3])
),
requirement_spec(
"Using 3 low tag bits needs at least 3 low tag bits to be available.",
(svar_low_tag_bits_use `being` svalue_low_tag_bits_use_3)
`implies_that`
(svar_ac_low_tag_bits_avail `is_one_of`
[svalue_ac_low_tag_bits_avail_3])
),
% Requirements of values of svar_stack_segments.
requirement_spec(
"Stack segments require the LLDS backend.",
(svar_stack_len `being` svalue_stack_len_segments) `implies_that`
(svar_backend `is_one_of` [svalue_backend_llds])
),
requirement_spec(
"Stack extension requires the LLDS backend.",
(svar_stack_len `being` svalue_stack_len_extend) `implies_that`
(svar_backend `is_one_of` [svalue_backend_llds])
),
% Requirements of values of svar_trail.
requirement_spec(
"Trailing requires targeting C.",
(svar_trail `being` svalue_trail_yes) `implies_that`
(svar_target `is_one_of` [svalue_target_c])
),
requirement_spec(
"Trailing interferes with minimal model tabling.",
(svar_trail `being` svalue_trail_yes) `implies_that`
(svar_minmodel `is_one_of` [svalue_minmodel_no])
),
% Requirements of values of svar_minmodel.
requirement_spec(
"Minimal model tabling requires the LLDS backend.",
(svar_minmodel `being` svalue_minmodel_stack_copy)
`implies_that`
(svar_backend `is_one_of` [svalue_backend_llds])
),
requirement_spec(
"Minimal model tabling requires the LLDS backend.",
(svar_minmodel `being` svalue_minmodel_stack_copy_debug)
`implies_that`
(svar_backend `is_one_of` [svalue_backend_llds])
),
requirement_spec(
"Minimal model tabling requires the LLDS backend.",
(svar_minmodel `being` svalue_minmodel_own_stack)
`implies_that`
(svar_backend `is_one_of` [svalue_backend_llds])
),
requirement_spec(
"Minimal model tabling requires the LLDS backend.",
(svar_minmodel `being` svalue_minmodel_own_stack_debug)
`implies_that`
(svar_backend `is_one_of` [svalue_backend_llds])
),
requirement_spec(
"Minimal model tabling requires Boehm-Demers-Weiser gc.",
(svar_minmodel `being` svalue_minmodel_stack_copy)
`implies_that`
(svar_gc `is_one_of`
[svalue_gc_none, svalue_gc_bdw, svalue_gc_bdw_debug])
),
requirement_spec(
"Minimal model tabling requires Boehm-Demers-Weiser gc.",
(svar_minmodel `being` svalue_minmodel_stack_copy_debug)
`implies_that`
(svar_gc `is_one_of`
[svalue_gc_none, svalue_gc_bdw, svalue_gc_bdw_debug])
),
requirement_spec(
"Minimal model tabling requires Boehm-Demers-Weiser gc.",
(svar_minmodel `being` svalue_minmodel_own_stack)
`implies_that`
(svar_gc `is_one_of`
[svalue_gc_none, svalue_gc_bdw, svalue_gc_bdw_debug])
),
requirement_spec(
"Minimal model tabling requires Boehm-Demers-Weiser gc.",
(svar_minmodel `being` svalue_minmodel_own_stack_debug)
`implies_that`
(svar_gc `is_one_of`
[svalue_gc_none, svalue_gc_bdw, svalue_gc_bdw_debug])
),
requirement_spec(
"Minimal model tabling does not respect thread safety.",
(svar_minmodel `being` svalue_minmodel_stack_copy)
`implies_that`
(svar_thread_safe `is_one_of` [svalue_thread_safe_c_no])
),
requirement_spec(
"Minimal model tabling does not respect thread safety.",
(svar_minmodel `being` svalue_minmodel_stack_copy_debug)
`implies_that`
(svar_thread_safe `is_one_of` [svalue_thread_safe_c_no])
),
% XXX Do svalue_minmodel_own_stack{,_debug} imply svalue_thread_safe_c_no?
% For now, since the implementation of own stack minimal model
% is not yet complete, we need not include its requirements in the list,
% and not including them should make constraint solving a tiny bit faster.
% Requirements of values of svar_thread_safe.
% None. There are some settings of other solver variables
% that are incompatible with thread safety, but those incompatibilities
% are expressed by requirements listed under the *other* solver variable.
% Requirements of values of svar_gc.
requirement_spec(
"Boehm-Demers-Weiser gc requires targeting C.",
(svar_gc `being` svalue_gc_bdw) `implies_that`
(svar_target `is_one_of` [svalue_target_c])
),
requirement_spec(
"Boehm-Demers-Weiser debug gc requires targeting C.",
(svar_gc `being` svalue_gc_bdw_debug) `implies_that`
(svar_target `is_one_of` [svalue_target_c])
),
requirement_spec(
"Accurate gc requires targeting C.",
(svar_gc `being` svalue_gc_accurate) `implies_that`
(svar_target `is_one_of` [svalue_target_c])
),
requirement_spec(
"Accurate gc conflicts with threading.",
(svar_gc `being` svalue_gc_accurate) `implies_that`
(svar_thread_safe `is_one_of` [svalue_thread_safe_c_no])
),
requirement_spec(
"History gc requires targeting C.",
(svar_gc `being` svalue_gc_history) `implies_that`
(svar_target `is_one_of` [svalue_target_c])
),
requirement_spec(
"History gc conflicts with threading.",
(svar_gc `being` svalue_gc_history) `implies_that`
(svar_thread_safe `is_one_of` [svalue_thread_safe_c_no])
),
% Requirements of values of svar_deep_prof.
requirement_spec(
"Deep profiling requires the LLDS backend.",
(svar_deep_prof `being` svalue_deep_prof_yes) `implies_that`
(svar_backend `is_one_of` [svalue_backend_llds])
),
requirement_spec(
"Deep profiling interferes with minimal model tabling.",
(svar_deep_prof `being` svalue_deep_prof_yes) `implies_that`
(svar_minmodel `is_one_of` [svalue_minmodel_no])
),
requirement_spec(
"Deep profiling does not work for multithreaded programs.",
(svar_deep_prof `being` svalue_deep_prof_yes) `implies_that`
(svar_thread_safe `is_one_of` [svalue_thread_safe_c_no])
),
requirement_spec(
"Deep profiling is incompatible with mprof call profiling.",
(svar_deep_prof `being` svalue_deep_prof_yes) `implies_that`
(svar_mprof_call `is_one_of` [svalue_mprof_call_no])
),
requirement_spec(
"Deep profiling is incompatible with mprof time profiling.",
(svar_deep_prof `being` svalue_deep_prof_yes) `implies_that`
(svar_mprof_time `is_one_of` [svalue_mprof_time_no])
),
requirement_spec(
"Deep profiling is incompatible with mprof memory profiling.",
(svar_deep_prof `being` svalue_deep_prof_yes) `implies_that`
(svar_mprof_memory `is_one_of` [svalue_mprof_memory_no])
),
% Requirements of values of svar_mprof_call.
requirement_spec(
"Mprof call profiling requires targeting C.",
(svar_mprof_call `being` svalue_mprof_call_yes) `implies_that`
(svar_target `is_one_of` [svalue_target_c])
),
requirement_spec(
"Mprof call profiling interferes with minimal model tabling.",
(svar_mprof_call `being` svalue_mprof_call_yes) `implies_that`
(svar_minmodel `is_one_of` [svalue_minmodel_no])
),
requirement_spec(
"Mprof call profiling does not work for multithreaded programs.",
(svar_mprof_call `being` svalue_mprof_call_yes) `implies_that`
(svar_thread_safe `is_one_of` [svalue_thread_safe_c_no])
),
% Requirements of values of svar_mprof_time.
requirement_spec(
"Mprof time profiling requires targeting C.",
(svar_mprof_time `being` svalue_mprof_time_yes) `implies_that`
(svar_target `is_one_of` [svalue_target_c])
),
requirement_spec(
"Mprof time profiling requires mprof call profiling.",
% XXX runtime/mercury_grade.h allows MR_MPROF_PROFILE_TIME without
% MR_MPROF_PROFILE_CALLS, but calls the combination "useless".
(svar_mprof_time `being` svalue_mprof_time_yes) `implies_that`
(svar_mprof_call `is_one_of` [svalue_mprof_call_yes])
),
% Requirements of values of svar_mprof_memory.
requirement_spec(
"Mprof memory profiling requires targeting C.",
(svar_mprof_memory `being` svalue_mprof_memory_yes) `implies_that`
(svar_target `is_one_of` [svalue_target_c])
),
requirement_spec(
"Mprof memory profiling requires mprof call profiling.",
(svar_mprof_memory `being` svalue_mprof_memory_yes) `implies_that`
(svar_mprof_call `is_one_of` [svalue_mprof_call_yes])
),
% Requirements of values of svar_tscope_prof.
requirement_spec(
"Threadscope style profiling requires the LLDS backend.",
(svar_tscope_prof `being` svalue_tscope_prof_yes) `implies_that`
(svar_backend `is_one_of` [svalue_backend_llds])
),
requirement_spec(
"Threadscope style profiling requires thread safe code.",
(svar_tscope_prof `being` svalue_tscope_prof_yes) `implies_that`
(svar_thread_safe `is_one_of` [svalue_thread_safe_c_yes])
),
% Requirements of values of svar_term_size_prof.
requirement_spec(
"Term size profiling requires the LLDS backend.",
(svar_term_size_prof `being` svalue_term_size_prof_cells) `implies_that`
(svar_backend `is_one_of` [svalue_backend_llds])
),
requirement_spec(
"Term size profiling requires the LLDS backend.",
(svar_term_size_prof `being` svalue_term_size_prof_words) `implies_that`
(svar_backend `is_one_of` [svalue_backend_llds])
),
requirement_spec(
"Term size profiling is incompatible with thread safety.",
(svar_term_size_prof `being` svalue_term_size_prof_cells) `implies_that`
(svar_thread_safe `is_one_of` [svalue_thread_safe_c_no])
),
requirement_spec(
"Term size profiling is incompatible with thread safety.",
(svar_term_size_prof `being` svalue_term_size_prof_words) `implies_that`
(svar_thread_safe `is_one_of` [svalue_thread_safe_c_no])
),
% Requirements of values of svar_debug.
requirement_spec(
"Debugging requires the LLDS backend.",
(svar_debug `being` svalue_debug_debug) `implies_that`
(svar_backend `is_one_of` [svalue_backend_llds])
),
requirement_spec(
"Declarative debugging requires the LLDS backend.",
(svar_debug `being` svalue_debug_decldebug) `implies_that`
(svar_backend `is_one_of` [svalue_backend_llds])
),
requirement_spec(
"Debugging does not work for multithreaded programs.",
(svar_debug `being` svalue_debug_debug) `implies_that`
(svar_thread_safe `is_one_of` [svalue_thread_safe_c_no])
),
requirement_spec(
"Declarative debugging does not work for multithreaded programs.",
(svar_debug `being` svalue_debug_decldebug) `implies_that`
(svar_thread_safe `is_one_of` [svalue_thread_safe_c_no])
),
% Requirements of values of svar_ssdebug.
requirement_spec(
"Source-to-source debugging does not make sense for the LLDS backend.",
(svar_ssdebug `being` svalue_ssdebug_yes) `implies_that`
(svar_backend `is_one_of` [svalue_backend_mlds])
),
requirement_spec(
"Source-to-source debugging does not work for multithreaded programs.",
(svar_ssdebug `being` svalue_ssdebug_yes) `implies_that`
(svar_thread_safe `is_one_of`
[svalue_thread_safe_c_no, svalue_thread_safe_target_native])
),
% Requirements of values of svar_target_debug.
% None. It should be applicable in all cases.
% Requirements of values of svar_rbmm.
requirement_spec(
"Region based memory management requires the LLDS backend.",
(svar_rbmm `being` svalue_rbmm_yes) `implies_that`
(svar_backend `is_one_of` [svalue_backend_llds])
),
% Requirements of values of svar_request_single_prec_float.
requirement_spec(
"Single precision floats are available only when targeting C.",
(svar_request_single_prec_float `being`
svalue_request_single_prec_float_yes)
`implies_that`
(svar_target `is_one_of` [svalue_target_c])
),
requirement_spec(
"Single precision floats are available when requested.",
% Since nothing forbids svalue_merc_float_is_unboxed_c_float,
% this implication should always succeed.
(svar_request_single_prec_float `being`
svalue_request_single_prec_float_yes)
`implies_that`
(svar_merc_float `is_one_of` [svalue_merc_float_is_unboxed_c_float])
),
% Requirements of values of svar_merc_float.
requirement_spec(
"Unboxed double precision floats require pointer-sized doubles.",
(svar_merc_float `being` svalue_merc_float_is_unboxed_c_double)
`implies_that`
(svar_ac_size_of_double `is_one_of` [svalue_ac_size_of_double_eq_ptr])
)
].
%---------------------------------------------------------------------------%
:- end_module grade_lib.grade_spec.
%---------------------------------------------------------------------------%