Files
mercury/compiler/handle_options.m
Simon Taylor 82c6cdb55e Make definitions of abstract types available when generating
Estimated hours taken: 100
Branches: main

Make definitions of abstract types available when generating
code for importing modules.  This is necessary for the .NET
back-end, and for `:- pragma export' on the C back-end.

compiler/prog_data.m:
compiler/modules.m:
compiler/make.dependencies.m:
compiler/recompilation.version.m:
	Handle implementation sections in interface files.

	There is a new pseudo-declaration `abstract_imported'
	which is applied to items from the implementation
	section of an interface file.  `abstract_imported'
	items may not be used in the error checking passes
	for the curent module.

compiler/equiv_type_hlds.m:
compiler/notes/compiler_design.html:
	New file.

	Go over the HLDS expanding all types fully after
	semantic checking has been run.

compiler/mercury_compile.m:
	Add the new pass.

	Don't write the `.opt' file if there are any errors.

compiler/instmap.m:
	Add a predicate instmap_delta_map_foldl to apply
	a procedure to all insts in an instmap.

compiler/equiv_type.m:
	Export predicates for use by equiv_type_hlds.m

	Reorder arguments so state variables and higher-order
	programming can be used.

compiler/prog_data.m:
compiler/prog_io_pragma.m:
compiler/make_hlds.m:
compiler/mercury_to_mercury.m:
	Handle `:- pragma foreign_type' as a form of type
	declaration rather than a pragma.

compiler/hlds_data.m:
compiler/*.m:
	Add a field to the type_info_cell_constructor cons_id
	to identify the type_ctor, which is needed by
	equiv_type_hlds.m.

compiler/module_qual.m:
	Donn't allow items from the implementation section of
	interface files to match items in the current module.

compiler/*.m:
tests/*/*.m:
	Add missing imports which only became apparent with
	the bug fixes above.

	Remove unnecessary imports which only became apparent with
	the bug fixes above.

tests/hard_coded/Mmakefile:
tests/hard_coded/export_test2.{m,exp}:
	Test case.

tests/invalid/Mmakefile:
tests/invalid/missing_interface_import2.{m,err_exp}:
	Test case.
2003-12-01 15:56:15 +00:00

1876 lines
67 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 1994-2003 The University of Melbourne.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%-----------------------------------------------------------------------------%
% File: handle_options.m.
% Main authors: fjh, zs.
% This module does post-procesing on the command-line options, after
% getopt has done its stuff.
% It also contains code for handling the --grade option.
%-----------------------------------------------------------------------------%
:- module libs__handle_options.
:- interface.
:- import_module libs__globals.
:- import_module libs__options.
:- import_module list, bool, getopt, std_util, io.
% handle_options(Args, MaybeError, OptionArgs, NonOptionArgs, Link).
:- pred handle_options(list(string), maybe(string), list(string),
list(string), bool, io__state, io__state).
:- mode handle_options(in, out, out, out, out, di, uo) is det.
% process_options(Args, OptionArgs, NonOptionArgs, MaybeOptionTable).
%
% Process the options, but don't do any post-processing or
% modify the globals. This is mainly useful for separating
% the list of arguments into option and non-option arguments.
:- pred process_options(list(string), list(string), list(string),
maybe_option_table(option)).
:- mode process_options(in, out, out, out) is det.
% usage_error(Descr, Message)
%
% Display the description of the error location, the error message
% and then a usage message.
:- pred usage_error(string::in, string::in,
io__state::di, io__state::uo) is det.
% usage_error(Message)
%
% Display error message and then usage message
:- pred usage_error(string::in, io__state::di, io__state::uo) is det.
% Display usage message.
:- pred usage(io__state::di, io__state::uo) is det.
% Display long usage message for help
:- pred long_usage(io__state::di, io__state::uo) is det.
% Given the current set of options, figure out
% which grade to use.
:- pred compute_grade(globals::in, string::out) is det.
% The inverse of compute_grade: given a grade,
% set the appropriate options.
:- pred convert_grade_option(string::in, option_table::in, option_table::out)
is semidet.
% Produce the grade component of grade-specific
% installation directories.
:- pred grade_directory_component(globals::in, string::out) is det.
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module libs__trace_params.
:- import_module parse_tree.
:- import_module parse_tree__prog_io_util.
:- import_module char, dir, int, string, map, set, library.
handle_options(Args0, MaybeError, OptionArgs, Args, Link) -->
% io__write_string("original arguments\n"),
% dump_arguments(Args0),
{ process_options(Args0, OptionArgs, Args, Result) },
% io__write_string("final arguments\n"),
% dump_arguments(Args),
postprocess_options(Result, MaybeError),
( { MaybeError = yes(_) } ->
{ Link = no }
;
globals__io_lookup_bool_option(generate_dependencies,
GenerateDependencies),
globals__io_lookup_bool_option(make_interface, MakeInterface),
globals__io_lookup_bool_option(make_private_interface,
MakePrivateInterface),
globals__io_lookup_bool_option(make_short_interface,
MakeShortInterface),
globals__io_lookup_bool_option(make_optimization_interface,
MakeOptimizationInt),
globals__io_lookup_bool_option(make_transitive_opt_interface,
MakeTransOptInt),
globals__io_lookup_bool_option(convert_to_mercury,
ConvertToMercury),
globals__io_lookup_bool_option(typecheck_only, TypecheckOnly),
globals__io_lookup_bool_option(errorcheck_only, ErrorcheckOnly),
globals__io_lookup_bool_option(target_code_only,
TargetCodeOnly),
globals__io_get_target(Target),
{ GenerateIL = (if Target = il then yes else no) },
{ GenerateJava = (if Target = java then yes else no) },
globals__io_lookup_bool_option(compile_only, CompileOnly),
globals__io_lookup_bool_option(aditi_only, AditiOnly),
{ bool__or_list([GenerateDependencies, MakeInterface,
MakePrivateInterface, MakeShortInterface,
MakeOptimizationInt, MakeTransOptInt,
ConvertToMercury, TypecheckOnly,
ErrorcheckOnly, TargetCodeOnly,
GenerateIL, GenerateJava,
CompileOnly, AditiOnly],
NotLink) },
{ bool__not(NotLink, Link) },
globals__io_lookup_bool_option(smart_recompilation, Smart),
( { Smart = yes, Link = yes } ->
% XXX Currently smart recompilation doesn't check
% that all the files needed to link are present
% and up-to-date, so disable it.
disable_smart_recompilation("linking")
;
[]
)
).
process_options(Args0, OptionArgs, Args, Result) :-
OptionOps = option_ops(short_option, long_option,
option_defaults, special_handler),
getopt__process_options(OptionOps, Args0,
OptionArgs, Args, Result).
:- pred dump_arguments(list(string), io__state, io__state).
:- mode dump_arguments(in, di, uo) is det.
dump_arguments([]) --> [].
dump_arguments([Arg | Args]) -->
io__write_string("<"),
io__write_string(Arg),
io__write_string(">\n"),
dump_arguments(Args).
%-----------------------------------------------------------------------------%
% Convert string-valued options into the appropriate enumeration types,
% and process implications among the options (i.e. situations where setting
% one option implies setting/unsetting another one).
:- pred postprocess_options(maybe_option_table(option), maybe(string),
io__state, io__state).
:- mode postprocess_options(in, out, di, uo) is det.
postprocess_options(error(ErrorMessage), yes(ErrorMessage)) --> [].
postprocess_options(ok(OptionTable), Error) -->
{ map__lookup(OptionTable, target, Target0) },
(
{ Target0 = string(TargetStr) },
{ convert_target(TargetStr, Target) }
->
{ map__lookup(OptionTable, gc, GC_Method0) },
(
{ GC_Method0 = string(GC_MethodStr) },
{ convert_gc_method(GC_MethodStr, GC_Method) }
->
{ map__lookup(OptionTable, tags, TagsMethod0) },
(
{ TagsMethod0 = string(TagsMethodStr) },
{ convert_tags_method(TagsMethodStr, TagsMethod) }
->
{ map__lookup(OptionTable, fact_table_hash_percent_full,
PercentFull) },
(
{ PercentFull = int(Percent) },
{ Percent >= 1 },
{ Percent =< 100 }
->
{ map__lookup(OptionTable, termination_norm,
TermNorm0) },
(
{ TermNorm0 = string(TermNormStr) },
{ convert_termination_norm(TermNormStr, TermNorm) }
->
{ map__lookup(OptionTable, trace, Trace) },
{ map__lookup(OptionTable, require_tracing,
RequireTracingOpt) },
{ map__lookup(OptionTable, decl_debug,
DeclDebugOpt) },
(
{ Trace = string(TraceStr) },
{ RequireTracingOpt = bool(RequireTracing) },
{ DeclDebugOpt = bool(DeclDebug) },
{ convert_trace_level(TraceStr, RequireTracing,
DeclDebug, MaybeTraceLevel) }
->
(
{ MaybeTraceLevel = yes(TraceLevel) },
{ map__lookup(OptionTable, suppress_trace,
Suppress) },
(
{ Suppress = string(SuppressStr) },
{ convert_trace_suppress(SuppressStr,
TraceSuppress) }
->
{ map__lookup(OptionTable, dump_hlds_alias,
DumpAliasOption) },
(
{ DumpAliasOption = string(DumpAlias) },
{ DumpAlias = "" }
->
postprocess_options_2(OptionTable,
Target, GC_Method, TagsMethod,
TermNorm, TraceLevel,
TraceSuppress, Error)
;
{ DumpAliasOption = string(DumpAlias) },
{ convert_dump_alias(DumpAlias,
DumpOptions) }
->
{ map__set(OptionTable,
dump_hlds_options,
string(DumpOptions),
NewOptionTable) },
postprocess_options_2(NewOptionTable,
Target, GC_Method, TagsMethod,
TermNorm, TraceLevel,
TraceSuppress, Error)
;
{ Error = yes("Invalid argument to option `--hlds-dump-alias'.") }
)
;
{ Error = yes("Invalid argument to option `--suppress-trace'.") }
)
;
{ MaybeTraceLevel = no },
{ Error = yes("Specified trace level is not compatible with grade") }
)
;
{ Error = yes("Invalid argument to option `--trace'\n\t(must be `minimum', `shallow', `deep', `decl', `rep' or `default').") }
)
;
{ Error = yes("Invalid argument to option `--termination-norm'\n\t(must be `simple', `total' or `num-data-elems').") }
)
;
{ Error = yes("Invalid argument to option `--fact-table-hash-percent-full'\n\t(must be an integer between 1 and 100)") }
)
;
{ Error = yes("Invalid tags option (must be `none', `low' or `high')") }
)
;
{ Error = yes("Invalid GC option (must be `none', `conservative', `boehm', `mps' or `accurate')") }
)
;
{ Error = yes("Invalid target option (must be `c', `asm', `il', or `java')") }
).
:- pred postprocess_options_2(option_table::in, compilation_target::in,
gc_method::in, tags_method::in, termination_norm::in,
trace_level::in, trace_suppress_items::in, maybe(string)::out,
io__state::di, io__state::uo) is det.
postprocess_options_2(OptionTable0, Target, GC_Method, TagsMethod,
TermNorm, TraceLevel, TraceSuppress, Error) -->
{ unsafe_promise_unique(OptionTable0, OptionTable1) }, % XXX
globals__io_init(OptionTable1, Target, GC_Method, TagsMethod,
TermNorm, TraceLevel, TraceSuppress),
% Conservative GC implies --no-reclaim-heap-*
( { gc_is_conservative(GC_Method) = yes } ->
globals__io_set_option(
reclaim_heap_on_semidet_failure, bool(no)),
globals__io_set_option(
reclaim_heap_on_nondet_failure, bool(no))
;
[]
),
% --tags none implies --num-tag-bits 0.
( { TagsMethod = none } ->
{ NumTagBits0 = 0 }
;
globals__io_lookup_int_option(num_tag_bits, NumTagBits0)
),
% if --tags low but --num-tag-bits not specified,
% use the autoconf-determined value for --num-tag-bits
% (the autoconf-determined value is passed from the `mc' script
% using the undocumented --conf-low-tag-bits option)
(
{ TagsMethod = low },
{ NumTagBits0 = -1 }
->
globals__io_lookup_int_option(conf_low_tag_bits, NumTagBits1)
;
{ NumTagBits1 = NumTagBits0 }
),
% if --num-tag-bits negative or unspecified, issue a warning
% and assume --num-tag-bits 0
( { NumTagBits1 < 0 } ->
io__progname_base("mercury_compile", ProgName),
report_warning(ProgName),
report_warning(
": warning: --num-tag-bits invalid or unspecified\n"),
io__write_string(ProgName),
report_warning(": using --num-tag-bits 0 (tags disabled)\n"),
{ NumTagBits = 0 }
;
{ NumTagBits = NumTagBits1 }
),
globals__io_set_option(num_tag_bits, int(NumTagBits)),
globals__io_lookup_bool_option(highlevel_data, HighLevelData),
globals__io_lookup_bool_option(automatic_intermodule_optimization,
AutoIntermodOptimization),
% Generating IL implies:
% - gc_method `none' and no heap reclamation on failure
% Because GC is handled automatically by the .NET CLR
% implementation.
% - high-level code
% Because only the MLDS back-end supports
% compiling to IL, not the LLDS back-end.
% - turning off nested functions
% Because IL doesn't support nested functions.
% - using copy-out for nondet output arguments
% For reasons explained in the paper "Compiling Mercury
% to the .NET Common Language Runtime"
% - using no tags
% Because IL doesn't provide any mechanism for tagging
% pointers.
% - boxing enums and disabling no_tag_types
% These are both required to ensure that we have a uniform
% representation (`object[]') for all data types,
% which is required to avoid type errors for code using
% abstract data types.
% XXX It should not be needed now that we have a general
% solution to the abstract equivalence type problem
% (intermodule optimization).
% But currently it is still needed, otherwise
% RTTI (e.g. construct, deconstruct) doesn't work
% for these types.
% - XXX it should also imply num_reserved_addresses = 1
% (we can use null pointers), but currently it doesn't,
% again because this causes problems with RTTI
% - no static ground terms
% XXX Previously static ground terms used to not work with
% --high-level-data. But this has been (mostly?) fixed now.
% So we should investigate re-enabling static ground terms.
% Currently mlds_to_il.m doesn't support them yet?
% - intermodule optimization
% This is only required for high-level data and is needed
% so that abstract equivalence types can be expanded. They
% need to be expanded because .NET requires that the structural
% representation of a type is known at all times.
% - dead procedure optimization
% intermodule optimization pulls in a lot of code which isn't
% needed, so ensure that this dead code is removed.
( { Target = il } ->
globals__io_set_gc_method(none),
globals__io_set_option(reclaim_heap_on_nondet_failure,
bool(no)),
globals__io_set_option(reclaim_heap_on_semidet_failure,
bool(no)),
globals__io_set_option(highlevel_code, bool(yes)),
globals__io_set_option(gcc_nested_functions, bool(no)),
globals__io_set_option(nondet_copy_out, bool(yes)),
globals__io_set_option(num_tag_bits, int(0)),
globals__io_set_option(unboxed_enums, bool(no)),
globals__io_set_option(unboxed_no_tag_types, bool(no)),
% globals__io_set_option(num_reserved_addresses, int(1))
globals__io_set_option(static_ground_terms, bool(no)),
( { HighLevelData = yes, AutoIntermodOptimization = yes } ->
globals__io_set_option(intermodule_optimization,
bool(yes)),
globals__io_set_option(optimize_dead_procs, bool(yes))
;
[]
),
% On the .NET backend we will be using a language independent
% debugger not mdb. Thus --debug has to imply --target-debug.
( { given_trace_level_is_none(TraceLevel) = no } ->
globals__io_set_option(target_debug, bool(yes))
;
[]
)
;
[]
),
% Set --put-nondet-env-on-heap if --verifiable-code is specified,
% unless both --il-funcptr-types and --il-refany-fields
% are specified.
globals__io_lookup_bool_option(il_funcptr_types, ILFuncPtrTypes),
globals__io_lookup_bool_option(il_refany_fields, ILRefAnyFields),
( { ILFuncPtrTypes = yes, ILRefAnyFields = yes } ->
[]
;
option_implies(verifiable_code, put_nondet_env_on_heap,
bool(yes))
),
% Generating Java implies
% - gc_method `none' and no heap reclamation on failure
% Because GC is handled automatically by the Java
% implementation.
% - high-level code
% Because only the MLDS back-end supports
% compiling to Java, not the LLDS back-end.
% - high-level data
% Because it is more efficient,
% and better for interoperability.
% (In theory --low-level-data should work too,
% but there's no reason to bother supporting it.)
% - turning off nested functions
% Because Java doesn't support nested functions.
% - using copy-out for both det and nondet output arguments
% Because Java doesn't support pass-by-reference.
% - using no tags
% Because Java doesn't provide any mechanism for tagging
% pointers.
% - box no-tag types
% We require no-tag types to be boxed since in Java
% java.lang.Object is the only type that all other types
% can be successfully cast to and then cast back from.
% - store nondet environments on the heap
% Because Java has no way of allocating structs on the stack.
% - no static ground terms
% XXX Previously static ground terms used to not work with
% --high-level-data. But this has been (mostly?) fixed now.
% So we should investigate re-enabling static ground terms.
% - intermodule optimization
% This is only required for high-level data and is needed
% so that abstract equivalence types can be expanded. They
% need to be expanded because Java requires that the structural
% representation of a type is known at all times.
% - dead procedure optimization
% intermodule optimization pulls in a lot of code which isn't
% needed, so ensure that this dead code is removed.
( { Target = java } ->
globals__io_set_gc_method(none),
globals__io_set_option(reclaim_heap_on_nondet_failure,
bool(no)),
globals__io_set_option(reclaim_heap_on_semidet_failure,
bool(no)),
globals__io_set_option(highlevel_code, bool(yes)),
globals__io_set_option(highlevel_data, bool(yes)),
globals__io_set_option(gcc_nested_functions, bool(no)),
globals__io_set_option(nondet_copy_out, bool(yes)),
globals__io_set_option(det_copy_out, bool(yes)),
globals__io_set_option(num_tag_bits, int(0)),
globals__io_set_option(unboxed_no_tag_types, bool(no)),
globals__io_set_option(static_ground_terms, bool(no)),
globals__io_set_option(put_nondet_env_on_heap, bool(yes)),
( { AutoIntermodOptimization = yes } ->
globals__io_set_option(intermodule_optimization,
bool(yes)),
globals__io_set_option(optimize_dead_procs, bool(yes))
;
[]
)
;
[]
),
% Generating assembler via the gcc back-end requires
% using high-level code.
( { Target = asm } ->
globals__io_set_option(highlevel_code, bool(yes))
;
[]
),
% Generating high-level C or asm code requires putting each commit
% in its own function, to avoid problems with setjmp() and
% non-volatile local variables.
( { Target = c ; Target = asm } ->
option_implies(highlevel_code, put_commit_in_own_func,
bool(yes))
;
[]
),
%
% Set up options for position independent code.
%
% Shared libraries always use `--linkage shared'.
option_implies(compile_to_shared_lib, pic, bool(yes)),
option_implies(compile_to_shared_lib, linkage, string("shared")),
option_implies(compile_to_shared_lib, mercury_linkage,
string("shared")),
% On x86, using PIC takes a register away from us.
option_implies(pic, pic_reg, bool(yes)),
% --high-level-code disables the use of low-level gcc extensions
option_implies(highlevel_code, gcc_non_local_gotos, bool(no)),
option_implies(highlevel_code, gcc_global_registers, bool(no)),
option_implies(highlevel_code, asm_labels, bool(no)),
% --no-gcc-nested-functions implies --no-gcc-local-labels
option_neg_implies(gcc_nested_functions, gcc_local_labels, bool(no)),
% --no-mlds-optimize implies --no-optimize-tailcalls
option_neg_implies(optimize, optimize_tailcalls, bool(no)),
% --rebuild is just like --make but always rebuilds the files
% without checking timestamps.
option_implies(rebuild, make, bool(yes)),
% make.m controls generating object code and linking itself,
% so mercury_compile.m should only generate target code when
% given a module to process.
option_implies(make, compile_only, bool(yes)),
option_implies(make, target_code_only, bool(yes)),
% This is needed for library installation (the library grades
% are built using `--use-grade-subdirs', and assume that
% the interface files were built using `--use-subdirs').
option_implies(make, use_subdirs, bool(yes)),
option_implies(invoked_by_mmc_make, use_subdirs, bool(yes)),
option_implies(invoked_by_mmc_make, make, bool(no)),
% --make handles creation of the module dependencies itself,
% and they don't need to be recreated when compiling to C.
option_implies(invoked_by_mmc_make,
generate_mmc_make_module_dependencies, bool(no)),
% --make does not handle --transitive-intermodule-optimization.
% --transitive-intermodule-optimization is in the process of
% being rewritten anyway.
option_implies(make, transitive_optimization, bool(no)),
option_implies(invoked_by_mmc_make, transitive_optimization, bool(no)),
( { \+ io__have_symlinks } ->
globals__io_set_option(use_symlinks, bool(no))
;
[]
),
option_implies(verbose_check_termination, check_termination,bool(yes)),
option_implies(check_termination, termination, bool(yes)),
option_implies(check_termination, warn_missing_trans_opt_files,
bool(yes)),
option_implies(make_transitive_opt_interface, transitive_optimization,
bool(yes)),
option_implies(transitive_optimization, intermodule_optimization,
bool(yes)),
option_implies(use_trans_opt_files, use_opt_files, bool(yes)),
% If we are doing full inter-module or transitive optimization,
% we need to build all `.opt' or `.trans_opt' files.
option_implies(intermodule_optimization, use_opt_files, bool(no)),
option_implies(transitive_optimization, use_trans_opt_files, bool(no)),
% XXX `--use-opt-files' is broken.
% When inter-module optimization is enabled, error checking
% without the extra information from the `.opt' files
% is done when making the `.opt' file. With `--use-opt-files',
% that doesn't happen.
globals__io_set_option(use_opt_files, bool(no)),
option_implies(smart_recompilation, generate_item_version_numbers,
bool(yes)),
option_implies(find_all_recompilation_reasons, verbose_recompilation,
bool(yes)),
%
% Disable `--smart-recompilation' for compilation options
% which either do not produce a compiled output file or
% for which smart recompilation will not work.
%
option_implies(generate_dependencies, smart_recompilation, bool(no)),
option_implies(convert_to_mercury, smart_recompilation, bool(no)),
option_implies(make_private_interface, smart_recompilation, bool(no)),
option_implies(make_interface, smart_recompilation, bool(no)),
option_implies(make_short_interface, smart_recompilation, bool(no)),
option_implies(output_grade_string, smart_recompilation, bool(no)),
option_implies(make_optimization_interface,
smart_recompilation, bool(no)),
option_implies(make_transitive_opt_interface,
smart_recompilation, bool(no)),
option_implies(errorcheck_only, smart_recompilation, bool(no)),
option_implies(typecheck_only, smart_recompilation, bool(no)),
% disable --line-numbers when building the `.int', `.opt', etc. files,
% since including line numbers in those would cause unnecessary
% recompilation
option_implies(make_private_interface, line_numbers, bool(no)),
option_implies(make_interface, line_numbers, bool(no)),
option_implies(make_short_interface, line_numbers, bool(no)),
option_implies(make_optimization_interface, line_numbers, bool(no)),
option_implies(make_transitive_opt_interface, line_numbers, bool(no)),
% `--aditi-only' is only used by the Aditi query shell,
% for queries which should only be compiled once.
% recompilation_check.m currently doesn't check whether
% the `.rlo' file is up to date (with `--no-aditi-only' the
% Aditi-RL bytecode is embedded in the `.c' file.
option_implies(aditi_only, smart_recompilation, bool(no)),
% We never use version number information in `.int3',
% `.opt' or `.trans_opt' files.
option_implies(make_short_interface, generate_item_version_numbers,
bool(no)),
% XXX Smart recompilation does not yet work with inter-module
% optimization, but we still want to generate version numbers
% in interface files for users of a library compiled with
% inter-module optimization but not using inter-module
% optimization themselves.
globals__io_lookup_bool_option(smart_recompilation, Smart),
maybe_disable_smart_recompilation(Smart, intermodule_optimization, yes,
"`--intermodule-optimization'"),
maybe_disable_smart_recompilation(Smart, use_opt_files, yes,
"`--use-opt-files'"),
% XXX Smart recompilation does not yet work with
% `--no-target-code-only'. With `--no-target-code-only'
% it becomes difficult to work out what all the target
% files are and check whether they are up-to-date.
% By default, mmake always enables `--target-code-only' and
% processes the target code file itself, so this isn't a problem.
maybe_disable_smart_recompilation(Smart, target_code_only, no,
"`--no-target-code-only'"),
option_implies(use_grade_subdirs, use_subdirs, bool(yes)),
option_implies(very_verbose, verbose, bool(yes)),
option_implies(verbose, verbose_commands, bool(yes)),
globals__io_lookup_int_option(debug_liveness, DebugLiveness),
(
{ DebugLiveness >= 0 },
{ convert_dump_alias("all", AllDumpOptions) }
->
% Programmers only enable --debug-liveness if they are
% interested in the goal annotations put on goals by
% the various phases of the liveness pass. The default
% dump options do not print these annotations.
globals__io_lookup_string_option(dump_hlds_options,
DumpOptions0),
{ string__append(DumpOptions0, AllDumpOptions, DumpOptions1) },
globals__io_set_option(dump_hlds_options, string(DumpOptions1))
;
[]
),
globals__io_lookup_int_option(dump_hlds_pred_id, DumpHLDSPredId),
( { DumpHLDSPredId >= 0 } ->
globals__io_lookup_string_option(dump_hlds_options,
DumpOptions2),
% Prevent the dumping of the mode and type tables.
{ string__replace_all(DumpOptions2, "M", "", DumpOptions3) },
{ string__replace_all(DumpOptions3, "T", "", DumpOptions) },
globals__io_set_option(dump_hlds_options, string(DumpOptions))
;
[]
),
% --split-c-files is not supported by the high-level C code generator.
option_implies(highlevel_code, split_c_files, bool(no)),
% --split-c-files implies --procs-per-c-function 1
option_implies(split_c_files, procs_per_c_function, int(1)),
% Minimal model tabling is not compatible with trailing;
% see the comment in runtime/mercury_tabling.c.
globals__io_lookup_bool_option(use_trail, UseTrail),
globals__io_lookup_bool_option(use_minimal_model, UseMinimalModel),
{ UseTrail = yes, UseMinimalModel = yes ->
Error = yes("trailing and minimal model tabling are not compatible")
;
Error = no
},
option_implies(target_debug, strip, bool(no)),
% --decl-debug is an extension of --debug
option_implies(decl_debug, require_tracing, bool(yes)),
option_implies(decl_debug, stack_trace, bool(yes)),
% The `.debug' grade (i.e. --stack-trace plus --require-tracing)
% implies --use-trail, except with --use-minimal-model, which is
% not compatible with --use-trail.
%
% The reason for this is to avoid unnecessary proliferation in
% the number of different grades. If you're using --debug,
% you've already taken a major performance hit, so you should
% be able to afford the minor performance hit caused by
% --use-trail.
globals__io_lookup_bool_option(stack_trace, StackTrace),
globals__io_lookup_bool_option(require_tracing, RequireTracing),
( { StackTrace = yes, RequireTracing = yes, UseMinimalModel = no } ->
globals__io_set_option(use_trail, bool(yes))
;
[]
),
% In debugging grades, we want to generate executables in which
% one can do retries across I/O safely.
option_implies(require_tracing, trace_table_io_all, bool(yes)),
% --trace-table-io-all is compulsory application of --trace-table-io
option_implies(trace_table_io_all, trace_table_io, bool(yes)),
% --trace-table-io-require is compulsory application of --trace-table-io
option_implies(trace_table_io_require, trace_table_io, bool(yes)),
% Execution tracing requires
% - disabling optimizations that would change
% the trace being generated (except with --trace-optimized)
% - enabling some low level optimizations to ensure consistent
% paths across optimization levels
% - enabling stack layouts
% - enabling typeinfo liveness
globals__io_lookup_bool_option(trace_optimized, TraceOptimized),
( { given_trace_level_is_none(TraceLevel) = no } ->
( { TraceOptimized = no } ->
% The following options modify the structure
% of the program, which makes it difficult to
% relate the trace to the source code (although
% it can be easily related to the transformed HLDS).
globals__io_set_option(inline_simple, bool(no)),
globals__io_set_option(inline_builtins, bool(no)),
globals__io_set_option(inline_single_use, bool(no)),
globals__io_set_option(inline_compound_threshold,
int(0)),
globals__io_set_option(optimize_unused_args, bool(no)),
globals__io_set_option(optimize_higher_order, bool(no)),
globals__io_set_option(type_specialization, bool(no)),
globals__io_set_option(user_guided_type_specialization,
bool(no)),
globals__io_set_option(deforestation, bool(no)),
globals__io_set_option(constraint_propagation,
bool(no)),
globals__io_set_option(local_constraint_propagation,
bool(no)),
globals__io_set_option(optimize_duplicate_calls,
bool(no)),
globals__io_set_option(optimize_constructor_last_call,
bool(no)),
globals__io_set_option(optimize_saved_vars_cell,
bool(no)),
globals__io_set_option(loop_invariants, bool(no)),
% For the IL backend we turn off optimize_peep
% so that we don't optimize away references to the
% local variables of a procedure.
( { Target = il } ->
globals__io_set_option(optimize_peep,
bool(no))
;
[]
)
;
[]
),
% Disable hijacks if debugging is enabled. The
% code we now use to restore the stacks for
% direct retries works only if the retry does not
% "backtrack" over a hijacked nondet stack frame
% whose hijack has not been undone. Note that
% code compiled without debugging may still hijack
% nondet stack frames. Execution may reemerge from
% the nondebugged region in one of two ways. If
% the nondebugged code returns, then it will have
% undone hijack, and the retry code will work. If
% the nondebugged code calls debugged code, there
% will be a region on the stacks containing no
% debugging information, and the retry command will
% refuse to perform retries that go into or beyond
% this region. Both cases preserve correctness.
%
% An alternative solution would be to store everything
% on the nondet stack that may be hijacked in ordinary
% stack slots on entry to every procedure, but that
% would be not only more complex than simply disabling
% hijacks, it would be slower as well, except in
% procedures that would have many nested hijacks,
% and such code is extremely rare.
globals__io_set_option(allow_hijacks, bool(no)),
% The following option prevents useless variables
% from cluttering the trace. Its explicit setting
% removes a source of variability in the goal paths
% reported by tracing.
globals__io_set_option(excess_assign, bool(yes)),
% The explicit setting of the following option
% removes a source of variability in the goal paths
% reported by tracing.
globals__io_set_option(follow_code, bool(yes)),
% The following option selects a special-case
% code generator that cannot (yet) implement tracing.
globals__io_set_option(middle_rec, bool(no)),
% The following options cause the info required
% by tracing to be generated.
globals__io_set_option(trace_stack_layout, bool(yes)),
globals__io_set_option(body_typeinfo_liveness, bool(yes)),
% To support up-level printing, we need to save
% variables across a call even if the call cannot
% succeed.
globals__io_set_option(opt_no_return_calls, bool(no))
;
[]
),
% Deep profiling will eventually use `procid' stack layouts,
% but for now, we use a separate copy of each MR_Proc_Id structure.
% option_implies(profile_deep, procid_stack_layout, bool(yes)),
globals__io_lookup_bool_option(profile_deep, ProfileDeep),
globals__io_lookup_bool_option(highlevel_code, HighLevel),
( { ProfileDeep = yes } ->
(
{ HighLevel = no },
{ Target = c }
->
[]
;
usage_error("deep profiling is incompatible with high level code")
),
globals__io_lookup_bool_option(
use_lots_of_ho_specialization, LotsOfHOSpec),
( { LotsOfHOSpec = yes } ->
{ True = bool(yes) },
globals__io_set_option(optimize_higher_order, True),
globals__io_set_option(higher_order_size_limit,
int(999999))
;
[]
)
;
[]
),
globals__io_lookup_bool_option(record_term_sizes_as_words,
RecordTermSizesAsWords),
globals__io_lookup_bool_option(record_term_sizes_as_cells,
RecordTermSizesAsCells),
(
{ RecordTermSizesAsWords = yes },
{ RecordTermSizesAsCells = yes }
->
usage_error("we can't record term size as both words and cells")
;
{ RecordTermSizesAsWords = yes
; RecordTermSizesAsCells = yes
},
{ HighLevel = yes }
->
usage_error("term size profiling is incompatible "
++ "with high level code")
;
[]
),
(
{ given_trace_level_is_none(TraceLevel) = yes
; HighLevel = no, Target = c
; Target = il
}
->
[]
;
usage_error("debugging is available only in low level C grades")
),
% The pthreads headers on some architectures (Solaris, Linux)
% don't work with -ansi.
option_implies(parallel, ansi_c, bool(no)),
% `--constant-propagation' effectively inlines builtins.
option_neg_implies(inline_builtins, constant_propagation, bool(no)),
% --no-reorder-conj implies --no-deforestation,
% --no-constraint-propagation and --no-local-constraint-propagation.
option_neg_implies(reorder_conj, deforestation, bool(no)),
option_neg_implies(reorder_conj, constraint_propagation, bool(no)),
option_neg_implies(reorder_conj, local_constraint_propagation,
bool(no)),
% --stack-trace requires `procid' stack layouts
option_implies(stack_trace, procid_stack_layout, bool(yes)),
% `trace' stack layouts need `procid' stack layouts
option_implies(trace_stack_layout, procid_stack_layout, bool(yes)),
% --gc accurate for the LLDS back-end requires `agc' stack layouts,
% typeinfo liveness, and needs hijacks, frameopt, and middle recursion
% optimization to be switched off.
% We also turn off optimization of stack slots for no_return calls,
% because that optimization does not preserve agc typeinfo liveness.
%
% For the MLDS back-end, `--gc accurate' requires just typeinfo
% liveness.
%
% XXX Currently we also need to disable heap reclamation on failure
% if accurate GC is enabled.
% There are two issues with heap reclamation on failure:
% (i) For heap reclamation on failure to work at all,
% we also need at least some degree of liveness-accuracy.
% Otherwise a local variable may get initialized to point
% to the heap, then the heap is reset, then the memory
% is overwritten with new allocations, and then a collection
% occurs, at which point the local variable now points to
% a value of the wrong type.
% (ii) The current method of handling saved heap pointers during GC
% means that we lose heap reclamation on failure after a
% GC occurs. A better method would be to just allocate a
% word of heap space at each choice point.
%
% XXX for the MLDS back-end,
% accurate GC currently also requires disabling the higher-order
% specialization pass, since that pass creates procedures
% which don't respect left-to-right scoping of type_info parameters,
% i.e. in which a parameter X may have a type whose type_info var
% (in the type_info_varmap) occurs to the right of X in the
% procedure's parameter list.
%
( { GC_Method = accurate } ->
globals__io_set_option(agc_stack_layout, bool(yes)),
globals__io_set_option(body_typeinfo_liveness, bool(yes)),
globals__io_set_option(allow_hijacks, bool(no)),
globals__io_set_option(optimize_frames, bool(no)),
globals__io_set_option(opt_no_return_calls, bool(no)),
globals__io_set_option(middle_rec, bool(no)),
globals__io_set_option(
reclaim_heap_on_semidet_failure, bool(no)),
globals__io_set_option(
reclaim_heap_on_nondet_failure, bool(no)),
option_implies(highlevel_code, optimize_higher_order, bool(no))
;
[]
),
% ml_gen_params_base and ml_declare_env_ptr_arg, in ml_code_util.m,
% both assume (for accurate GC) that continuation environments
% are always allocated on the stack, which means that things won't
% if --gc accurate and --put-nondet-env-on-heap are both enabled.
globals__io_lookup_bool_option(put_nondet_env_on_heap,
PutNondetEnvOnHeap),
(
{ HighLevel = yes },
{ GC_Method = accurate },
{ PutNondetEnvOnHeap = yes }
->
usage_error("--gc accurate is incompatible with " ++
"--put-nondet-env-on-heap")
;
[]
),
% `procid' and `agc' stack layouts need `basic' stack layouts
option_implies(procid_stack_layout, basic_stack_layout, bool(yes)),
option_implies(agc_stack_layout, basic_stack_layout, bool(yes)),
% dupelim.m doesn't preserve label layout structures
% (e.g. it can change the return address in a call
% to a different label whose code is the same but
% which has a different label layout structure),
% so we need to disable it when tracing.
option_implies(procid_stack_layout, optimize_dups, bool(no)),
% likewise for accurate GC
option_implies(agc_stack_layout, optimize_dups, bool(no)),
% XXX deforestation and constraint propagation do not perform
% folding on polymorphic predicates correctly with
% --body-typeinfo-liveness.
option_implies(body_typeinfo_liveness, deforestation, bool(no)),
option_implies(body_typeinfo_liveness, constraint_propagation,
bool(no)),
% XXX if trailing is enabled, middle recursion optimization
% can generate code which does not allocate a stack frame
% even though stack slots are used to save and restore the
% trail, if the code being optimized contains a construct which
% might save/restore the trail state, i.e. an if-then-else,
% negation, disjunction, or commit.
option_implies(use_trail, middle_rec, bool(no)),
% Minimal model tabling needs to be able to rewrite all the redoips
% in a given nondet stack segments. If we allow hijacks, some of these
% redoips may have been saved in ordinary framevars, which means that
% tabling can't find them without label layout info. Since we want
% to allow tabling in grades that do not have label layout info,
% we disable hijacks instead.
option_implies(use_minimal_model, allow_hijacks, bool(no)),
% --dump-hlds and --statistics require compilation by phases
globals__io_lookup_accumulating_option(dump_hlds, DumpStages),
globals__io_lookup_bool_option(statistics, Statistics),
( { DumpStages \= [] ; Statistics = yes } ->
globals__io_set_option(trad_passes, bool(no))
;
[]
),
% If we are doing type-specialization, we may as well take
% advantage of the declarations supplied by the programmer.
option_implies(type_specialization, user_guided_type_specialization,
bool(yes)),
% The local constraint propagation transformation (constraint.m)
% is a required part of the constraint propagation transformation
% performed by deforest.m.
option_implies(constraint_propagation, local_constraint_propagation,
bool(yes)),
% --intermod-unused-args implies --intermodule-optimization and
% --optimize-unused-args.
option_implies(intermod_unused_args, intermodule_optimization,
bool(yes)),
option_implies(intermod_unused_args, optimize_unused_args, bool(yes)),
% --introduce-accumulators implies --excess-assign and
% --common-struct.
option_implies(introduce_accumulators, excess_assign, bool(yes)),
option_implies(introduce_accumulators, common_struct, bool(yes)),
% Don't do the unused_args optimization when making the
% optimization interface.
option_implies(make_optimization_interface, optimize_unused_args,
bool(no)),
% The information needed for generating the module ordering
% is only available while generating the dependencies.
option_implies(generate_module_order, generate_dependencies,
bool(yes)),
% We only generate the source file mapping if the module name
% doesn't match the file name.
option_implies(generate_source_file_mapping, warn_wrong_module_name,
bool(no)),
% --aditi-only implies --aditi.
option_implies(aditi_only, aditi, bool(yes)),
% Set --aditi-user to the value of $USER if it is not set already.
% If $USER is not set, use the string "guest".
globals__io_lookup_string_option(aditi_user, User0),
( { User0 = "" } ->
io__get_environment_var("USER", MaybeUser),
( { MaybeUser = yes(User1) } ->
{ User = User1 }
;
{ User = "guest" }
),
globals__io_set_option(aditi_user, string(User))
;
[]
),
globals__io_lookup_string_option(fullarch, FullArch),
%
% Add the standard library directory.
%
globals__io_lookup_maybe_string_option(
mercury_standard_library_directory, MaybeStdLibDir),
( { MaybeStdLibDir = yes(StdLibDir) } ->
globals__io_get_globals(Globals2),
{ globals__get_options(Globals2, OptionTable2) },
{ globals__set_options(Globals2,
option_table_add_mercury_library_directory(
OptionTable2, StdLibDir),
Globals3) },
{ unsafe_promise_unique(Globals3, Globals4) },
globals__io_set_globals(Globals4),
%
% Add `-L' and `-R' options for the location
% of the GC libraries.
%
globals__io_lookup_accumulating_option(
link_library_directories, LinkLibDirs0),
globals__io_set_option(link_library_directories,
accumulating(
[StdLibDir/"lib"/FullArch | LinkLibDirs0])),
globals__io_lookup_accumulating_option(
runtime_link_library_directories, Rpath0),
globals__io_set_option(runtime_link_library_directories,
accumulating([StdLibDir/"lib"/FullArch | Rpath0]))
;
[]
),
%
% Add the path to mercury_conf.h.
%
globals__io_lookup_maybe_string_option(
mercury_configuration_directory, MaybeConfDir),
( { MaybeConfDir = yes(ConfDir) } ->
globals__io_lookup_accumulating_option(c_include_directory,
CIncludeDirs0),
globals__io_set_option(c_include_directory,
accumulating([ConfDir/"conf" | CIncludeDirs0]))
;
[]
),
%
% Find the configuration file.
%
globals__io_lookup_maybe_string_option(config_file, ConfigFile),
% yes("") means `--config-file' was not passed on the command line.
( { ConfigFile = yes("") } ->
( { MaybeConfDir = yes(ConfDir1) } ->
globals__io_set_option(config_file, maybe_string(yes(
ConfDir1/"conf"/"Mercury.config")))
;
globals__io_set_option(config_file, maybe_string(no))
)
;
[]
),
%
% Handle the `.opt', C header and library search directories.
% These couldn't be handled by options.m because they are grade
% dependent.
%
globals__io_lookup_accumulating_option(mercury_library_directories,
MercuryLibDirs),
globals__io_get_globals(Globals),
{ grade_directory_component(Globals, GradeString) },
(
{ MercuryLibDirs = [_|_] },
{ ExtraLinkLibDirs = list__map(
(func(MercuryLibDir) =
MercuryLibDir/"lib"/GradeString/FullArch
), MercuryLibDirs) },
globals__io_lookup_accumulating_option(
link_library_directories, LinkLibDirs),
globals__io_set_option(link_library_directories,
accumulating(LinkLibDirs ++ ExtraLinkLibDirs)),
globals__io_lookup_accumulating_option(
runtime_link_library_directories, Rpath),
globals__io_set_option(runtime_link_library_directories,
accumulating(Rpath ++ ExtraLinkLibDirs)),
{ ExtraCIncludeDirs = list__map(
(func(MercuryLibDir) =
MercuryLibDir/"lib"/GradeString/FullArch/"inc"
), MercuryLibDirs) },
globals__io_lookup_accumulating_option(c_include_directory,
CIncludeDirs),
globals__io_set_option(c_include_directory,
accumulating(ExtraCIncludeDirs ++ CIncludeDirs)),
{ ExtraIntermodDirs = list__map(
(func(MercuryLibDir) =
dir__make_path_name(MercuryLibDir,
dir__make_path_name("ints",
GradeString
))
), MercuryLibDirs) },
globals__io_lookup_accumulating_option(intermod_directories,
IntermodDirs0),
globals__io_set_option(intermod_directories,
accumulating(ExtraIntermodDirs ++ IntermodDirs0))
;
{ MercuryLibDirs = [] }
),
% If --use-search-directories-for-intermod is true, append the
% search directories to the list of directories to search for
% .opt files.
globals__io_lookup_bool_option(use_search_directories_for_intermod,
UseSearchDirs),
( { UseSearchDirs = yes } ->
globals__io_lookup_accumulating_option(intermod_directories,
IntermodDirs1),
globals__io_lookup_accumulating_option(search_directories,
SearchDirs),
globals__io_set_option(intermod_directories,
accumulating(IntermodDirs1 ++ SearchDirs))
;
[]
),
globals__io_lookup_bool_option(use_grade_subdirs, UseGradeSubdirs),
( { UseGradeSubdirs = yes } ->
%
% With `--use-grade-subdirs', `.opt', `.trans_opt' and
% `.mih' files are placed in a directory named
% `Mercury/<grade>/<fullarch>/Mercury/<ext>s'.
% When searching for a `.opt' file, module_name_to_file_name
% produces `Mercury/<ext>/<module>.ext' so that searches
% for installed files work, so we need to add
% `--intermod-directory Mercury/<grade>/<fullarch>'
% to find the `.opt' files in the current directory.
%
globals__io_lookup_accumulating_option(intermod_directories,
IntermodDirs2),
{ GradeSubdirIntermodDirs =
["Mercury"/GradeString/FullArch |
list__filter(isnt(unify(dir__this_directory)),
IntermodDirs2)] },
globals__io_set_option(intermod_directories,
accumulating(GradeSubdirIntermodDirs))
;
[]
),
%
% When searching for a header (.mh or .mih) file,
% module_name_to_file_name uses the plain header
% name, so we need to add the full path to the
% header files in the current directory.
%
globals__io_lookup_bool_option(use_subdirs, UseSubdirs),
(
{ UseGradeSubdirs = yes ->
MihsSubdir =
"Mercury"/GradeString/FullArch/"Mercury"/"mihs"
; UseSubdirs = yes ->
MihsSubdir = "Mercury"/"mihs"
;
fail
}
->
globals__io_lookup_accumulating_option(c_include_directory,
CIncludeDirs1),
{ SubdirCIncludeDirs =
[dir__this_directory, MihsSubdir | CIncludeDirs1] },
globals__io_set_option(c_include_directory,
accumulating(SubdirCIncludeDirs))
;
[]
),
% --use-opt-files implies --no-warn-missing-opt-files since
% we are expecting some to be missing.
option_implies(use_opt_files, warn_missing_opt_files, bool(no)),
% --warn-non-tail-recursion requires both --high-level-code
% and --optimize-tailcalls. It also doesn't work if you use
% --errorcheck-only.
option_requires(warn_non_tail_recursion, highlevel_code, bool(yes),
"--warn-non-tail-recursion requires --high-level-code"),
option_requires(warn_non_tail_recursion, optimize_tailcalls, bool(yes),
"--warn-non-tail-recursion requires --optimize-tailcalls"),
option_requires(warn_non_tail_recursion, errorcheck_only, bool(no),
"--warn-non-tail-recursion is incompatible with --errorcheck-only"),
% The backend foreign languages depend on the target.
(
{ Target = c },
{ BackendForeignLanguages = ["c"] }
;
{ Target = il },
{ BackendForeignLanguages = ["il", "csharp", "mc++"] }
;
{ Target = asm },
% XXX This is wrong! It should be asm.
{ BackendForeignLanguages = ["c"] }
;
{ Target = java },
{ BackendForeignLanguages = ["java"] }
),
% only set the backend foreign languages if they are unset
globals__io_lookup_accumulating_option(backend_foreign_languages,
CurrentBackendForeignLanguage),
(
{ CurrentBackendForeignLanguage = [] }
->
globals__io_set_option(backend_foreign_languages,
accumulating(BackendForeignLanguages))
;
[]
),
globals__io_lookup_int_option(compare_specialization, CompareSpec),
( { CompareSpec < 0 } ->
% This indicates that the option was not set by the user;
% we should set the option to the default value. This value
% may be back end specific, since different back ends have
% different performance tradeoffs.
(
{ HighLevel = no },
globals__io_set_option(compare_specialization, int(13))
;
{ HighLevel = yes },
globals__io_set_option(compare_specialization, int(14))
)
;
[]
),
( { HighLevel = no } ->
postprocess_options_lowlevel
;
[]
).
% These option implications only affect the low-level (LLDS) code
% generator. They may in fact be harmful if set for the high-level
% code generator, because sometimes the same option has different
% meanings and implications in the two backends.
%
:- pred postprocess_options_lowlevel(io__state::di, io__state::uo) is det.
postprocess_options_lowlevel -->
% The low level code generator assumes that const(_) rvals are
% really constant, and that create(_) rvals with constant
% arguments can be materialized in an assignable rval without
% further code. For float_consts, the former is true only if
% either static_ground_terms or unboxed_floats is true, and
% the latter cannot be true without static_ground_terms.
option_neg_implies(highlevel_code, static_ground_terms, bool(yes)),
% --optimize-saved-vars-cell requires --use-local-vars for
% acceptable performance.
option_implies(optimize_saved_vars_cell, use_local_vars, bool(yes)),
% --optimize-frames requires --optimize-labels and
% --optimize-jumps
option_implies(optimize_frames, optimize_labels, bool(yes)),
option_implies(optimize_frames, optimize_jumps, bool(yes)).
% option_implies(SourceBoolOption, ImpliedOption, ImpliedOptionValue, IO0, IO).
% If the SourceBoolOption is set to yes, then the ImpliedOption is set
% to ImpliedOptionValue.
:- pred option_implies(option::in, option::in, option_data::in,
io__state::di, io__state::uo) is det.
option_implies(SourceOption, ImpliedOption, ImpliedOptionValue) -->
globals__io_lookup_bool_option(SourceOption, SourceOptionValue),
( { SourceOptionValue = yes } ->
globals__io_set_option(ImpliedOption, ImpliedOptionValue)
;
[]
).
% option_neg_implies(SourceBoolOption, ImpliedOption,
% ImpliedOptionValue, IO0, IO).
% If the SourceBoolOption is set to no, then the ImpliedOption is set
% to ImpliedOptionValue.
:- pred option_neg_implies(option::in, option::in, option_data::in,
io__state::di, io__state::uo) is det.
option_neg_implies(SourceOption, ImpliedOption, ImpliedOptionValue) -->
globals__io_lookup_bool_option(SourceOption, SourceOptionValue),
( { SourceOptionValue = no } ->
globals__io_set_option(ImpliedOption, ImpliedOptionValue)
;
[]
).
% option_requires(SourceBoolOption, RequiredOption, RequiredOptionValue,
% ErrorMsg):
% If the SourceBoolOption is set to yes, and RequiredOption is not set
% to RequiredOptionValue, then report a usage error.
:- pred option_requires(option::in, option::in, option_data::in,
string::in, io__state::di, io__state::uo) is det.
option_requires(SourceOption, RequiredOption, RequiredOptionValue,
ErrorMessage) -->
globals__io_lookup_bool_option(SourceOption, SourceOptionValue),
globals__io_lookup_option(RequiredOption, OptionValue),
( { SourceOptionValue = yes, OptionValue \= RequiredOptionValue } ->
usage_error(ErrorMessage)
;
[]
).
% Smart recompilation does not yet work with all
% options (in particular `--intermodule-optimization'
% and `--no-target-code-only'). Disable smart recompilation
% if such an option is set, maybe issuing a warning.
:- pred maybe_disable_smart_recompilation(bool::in, option::in, bool::in,
string::in, io__state::di, io__state::uo) is det.
maybe_disable_smart_recompilation(Smart, ConflictingOption,
ValueToDisableSmart, OptionDescr) -->
globals__io_lookup_bool_option(ConflictingOption, Value),
(
{ Smart = yes },
{ Value = ValueToDisableSmart }
->
disable_smart_recompilation(OptionDescr)
;
[]
).
:- pred disable_smart_recompilation(string::in,
io__state::di, io__state::uo) is det.
disable_smart_recompilation(OptionDescr) -->
globals__io_set_option(smart_recompilation, bool(no)),
globals__io_lookup_bool_option(warn_smart_recompilation,
WarnSmart),
( { WarnSmart = yes } ->
io__write_string(
"Warning: smart recompilation does not yet work with "),
io__write_string(OptionDescr),
io__write_string(".\n"),
globals__io_lookup_bool_option(halt_at_warn, Halt),
( { Halt = yes } ->
io__set_exit_status(1)
;
[]
)
;
[]
).
usage_error(ErrorDescr, ErrorMessage) -->
write_program_name,
io__write_string(ErrorDescr),
io__nl,
usage_error(ErrorMessage).
usage_error(ErrorMessage) -->
write_program_name,
io__write_string(ErrorMessage),
io__write_string("\n"),
io__set_exit_status(1),
usage.
:- pred write_program_name(io__state::di, io__state::uo) is det.
write_program_name -->
io__progname_base("mercury_compile", ProgName),
io__write_string(ProgName),
io__write_string(": ").
usage -->
{ library__version(Version) },
io__write_strings([
"Mercury Compiler, version ", Version, "\n",
"Copyright (C) 1993-2002 The University of Melbourne\n",
"Usage: mmc [<options>] <arguments>\n",
"Use `mmc --help' for more information.\n"
]).
long_usage -->
{ library__version(Version) },
io__write_strings(["Mercury Compiler, version ", Version, "\n"]),
io__write_string("Copyright (C) 1993-2002 The University of Melbourne\n"),
io__write_string("Usage: mmc [<options>] <arguments>\n"),
io__write_string("Arguments:\n"),
io__write_string("\tArguments ending in `.m' are assumed to be source file names.\n"),
io__write_string("\tArguments that do not end in `.m' are assumed to be module names.\n"),
io__write_string("Options:\n"),
options_help.
%-----------------------------------------------------------------------------%
% IMPORTANT: any changes here may require similar changes to
% runtime/mercury_grade.h
% scripts/parse_grade_options.sh-subr
% scripts/canonical_grade.sh-subr
%
% The grade_component type should have one constructor for each
% dimension of the grade. It is used when converting the components
% of the grade string to make sure the grade string doesn't contain
% more than one value for each dimension (eg *.gc.agc).
% Adding a value here will require adding clauses to the
% grade_component_table.
%
% A --grade option causes all the grade dependent options to be
% reset, and only those described by the grade string to be set.
% The value to which a grade option should be reset should be given
% in the grade_start_values table below.
%
% The ordering of the components here is the same as the order
% used in scripts/ml.in, and any change here will require a
% corresponding change there. The only place where the ordering
% actually matters is for constructing the pathname for the
% grade of the library, etc for linking (and installation).
:- type grade_component
---> gcc_ext % gcc extensions etc. -- see
% grade_component_table
; par % parallelism / multithreading
; gc % the kind of GC to use
; prof % what profiling options to use
; term_size % whether or not to record term sizes
; trail % whether or not to use trailing
; tag % whether or not to reserve a tag
; minimal_model % whether we set up for minimal model tabling
; pic % Do we need to reserve a register for
% PIC (position independent code)?
; trace % tracing/debugging options
.
convert_grade_option(GradeString, Options0, Options) :-
reset_grade_options(Options0, Options1),
split_grade_string(GradeString, Components),
set__init(NoComps),
list__foldl2((pred(CompStr::in, Opts0::in, Opts::out,
CompSet0::in, CompSet::out) is semidet :-
grade_component_table(CompStr, Comp, CompOpts, MaybeTargets),
% Check that the component isn't mentioned
% more than once.
\+ set__member(Comp, CompSet0),
set__insert(CompSet0, Comp, CompSet),
add_option_list(CompOpts, Opts0, Opts1),
% XXX Here the behaviour matches what used to happen
% and that is to only set the target option iff there
% was only one possible target. Is this a bug?
( MaybeTargets = yes([Target]) ->
add_option_list([target - Target], Opts1, Opts)
;
Opts = Opts1
)
), Components, Options1, Options, NoComps, _FinalComps).
:- pred add_option_list(list(pair(option, option_data)), option_table,
option_table).
:- mode add_option_list(in, in, out) is det.
add_option_list(CompOpts, Opts0, Opts) :-
list__foldl((pred(Opt::in, Opts1::in, Opts2::out) is det :-
Opt = Option - Data,
map__set(Opts1, Option, Data, Opts2)
), CompOpts, Opts0, Opts).
grade_directory_component(Globals, Grade) :-
compute_grade(Globals, Grade0),
%
% Strip out the `.picreg' part of the grade -- `.picreg' is
% implied by the file names (.pic_o vs .o, `.a' vs `.so').
%
(
string__sub_string_search(Grade0,
".picreg", PicRegIndex),
string__split(Grade0, PicRegIndex,
LeftPart, RightPart0),
string__append(".picreg", RightPart, RightPart0)
->
Grade = LeftPart ++ RightPart
;
Grade = Grade0
).
compute_grade(Globals, Grade) :-
globals__get_options(Globals, Options),
compute_grade_components(Options, Components),
(
Components = [],
Grade = "none"
;
Components = [_|_],
construct_string(Components, Grade)
).
:- pred construct_string(list(pair(grade_component, string)), string).
:- mode construct_string(in, out) is det.
construct_string([], "").
construct_string([_ - Bit|Bits], Grade) :-
(
Bits = [_|_],
construct_string(Bits, Grade0),
string__append_list([Bit, ".", Grade0], Grade)
;
Bits = [],
Grade = Bit
).
:- pred compute_grade_components(option_table,
list(pair(grade_component, string))).
:- mode compute_grade_components(in, out) is det.
compute_grade_components(Options, GradeComponents) :-
solutions((pred(CompData::out) is nondet :-
grade_component_table(Name, Comp, CompOpts, MaybeTargets),
% For possible component of the grade string
% include it in the actual grade string if all
% the option setting that it implies are true.
% ie
% all [Opt, Value] (
% member(Opt - Value, CompOpts) =>
% map__search(Options, Opt, Value)
% )
\+ (
list__member(Opt - Value, CompOpts),
\+ map__search(Options, Opt, Value)
),
% When checking gcc_ext there exist grades which
% can have more then one possible target, ensure that
% the target in the options table matches one of the
% possible targets.
( MaybeTargets = yes(Targets) ->
list__member(Target, Targets),
map__search(Options, target, Target)
;
true
),
CompData = Comp - Name
), GradeComponents).
:- pred grade_component_table(string, grade_component,
list(pair(option, option_data)), maybe(list(option_data))).
:- mode grade_component_table(in, out, out, out) is semidet.
:- mode grade_component_table(out, in, out, out) is multi.
:- mode grade_component_table(out, out, out, out) is multi.
% Base components
% These specify the basic compilation model we use,
% including the choice of back-end and the use of gcc extensions.
grade_component_table("none", gcc_ext, [
asm_labels - bool(no),
gcc_non_local_gotos - bool(no),
gcc_global_registers - bool(no),
highlevel_code - bool(no),
gcc_nested_functions - bool(no),
highlevel_data - bool(no)],
yes([string("c")])).
grade_component_table("reg", gcc_ext, [
asm_labels - bool(no),
gcc_non_local_gotos - bool(no),
gcc_global_registers - bool(yes),
highlevel_code - bool(no),
gcc_nested_functions - bool(no),
highlevel_data - bool(no)],
yes([string("c")])).
grade_component_table("jump", gcc_ext, [
asm_labels - bool(no),
gcc_non_local_gotos - bool(yes),
gcc_global_registers - bool(no),
highlevel_code - bool(no),
gcc_nested_functions - bool(no),
highlevel_data - bool(no)],
yes([string("c")])).
grade_component_table("asm_jump", gcc_ext, [
asm_labels - bool(yes),
gcc_non_local_gotos - bool(yes),
gcc_global_registers - bool(no),
highlevel_code - bool(no),
gcc_nested_functions - bool(no),
highlevel_data - bool(no)],
yes([string("c")])).
grade_component_table("fast", gcc_ext, [
asm_labels - bool(no),
gcc_non_local_gotos - bool(yes),
gcc_global_registers - bool(yes),
highlevel_code - bool(no),
gcc_nested_functions - bool(no),
highlevel_data - bool(no)],
yes([string("c")])).
grade_component_table("asm_fast", gcc_ext, [
asm_labels - bool(yes),
gcc_non_local_gotos - bool(yes),
gcc_global_registers - bool(yes),
highlevel_code - bool(no),
gcc_nested_functions - bool(no),
highlevel_data - bool(no)],
yes([string("c")])).
grade_component_table("hl", gcc_ext, [
asm_labels - bool(no),
gcc_non_local_gotos - bool(no),
gcc_global_registers - bool(no),
highlevel_code - bool(yes),
gcc_nested_functions - bool(no),
highlevel_data - bool(yes)],
yes([string("c"), string("asm")])).
grade_component_table("hlc", gcc_ext, [
asm_labels - bool(no),
gcc_non_local_gotos - bool(no),
gcc_global_registers - bool(no),
highlevel_code - bool(yes),
gcc_nested_functions - bool(no),
highlevel_data - bool(no)],
yes([string("c"), string("asm")])).
grade_component_table("hl_nest", gcc_ext, [
asm_labels - bool(no),
gcc_non_local_gotos - bool(no),
gcc_global_registers - bool(no),
highlevel_code - bool(yes),
gcc_nested_functions - bool(yes),
highlevel_data - bool(yes)],
yes([string("c"), string("asm")])).
grade_component_table("hlc_nest", gcc_ext, [
asm_labels - bool(no),
gcc_non_local_gotos - bool(no),
gcc_global_registers - bool(no),
highlevel_code - bool(yes),
gcc_nested_functions - bool(yes),
highlevel_data - bool(no)],
yes([string("c"), string("asm")])).
grade_component_table("il", gcc_ext, [
asm_labels - bool(no),
gcc_non_local_gotos - bool(no),
gcc_global_registers - bool(no),
highlevel_code - bool(yes),
gcc_nested_functions - bool(no),
highlevel_data - bool(yes)],
yes([string("il")])).
grade_component_table("ilc", gcc_ext, [
asm_labels - bool(no),
gcc_non_local_gotos - bool(no),
gcc_global_registers - bool(no),
highlevel_code - bool(yes),
gcc_nested_functions - bool(no),
highlevel_data - bool(no)],
yes([string("il")])).
grade_component_table("java", gcc_ext, [
asm_labels - bool(no),
gcc_non_local_gotos - bool(no),
gcc_global_registers - bool(no),
gcc_nested_functions - bool(no),
highlevel_code - bool(yes),
highlevel_data - bool(yes)],
yes([string("java")])).
% Parallelism/multithreading components.
grade_component_table("par", par, [parallel - bool(yes)], no).
% GC components
grade_component_table("gc", gc, [gc - string("boehm")], no).
grade_component_table("mps", gc, [gc - string("mps")], no).
grade_component_table("agc", gc, [gc - string("accurate")], no).
% Profiling components
grade_component_table("prof", prof,
[profile_time - bool(yes), profile_calls - bool(yes),
profile_memory - bool(no), profile_deep - bool(no)], no).
grade_component_table("proftime", prof,
[profile_time - bool(yes), profile_calls - bool(no),
profile_memory - bool(no), profile_deep - bool(no)], no).
grade_component_table("profcalls", prof,
[profile_time - bool(no), profile_calls - bool(yes),
profile_memory - bool(no), profile_deep - bool(no)], no).
grade_component_table("memprof", prof,
[profile_time - bool(no), profile_calls - bool(yes),
profile_memory - bool(yes), profile_deep - bool(no)], no).
grade_component_table("profall", prof,
[profile_time - bool(yes), profile_calls - bool(yes),
profile_memory - bool(yes), profile_deep - bool(no)], no).
grade_component_table("profdeep", prof,
[profile_time - bool(no), profile_calls - bool(no),
profile_memory - bool(no), profile_deep - bool(yes)], no).
% Term size components
grade_component_table("tsw", term_size,
[record_term_sizes_as_words - bool(yes),
record_term_sizes_as_cells - bool(no)], no).
grade_component_table("tsc", term_size,
[record_term_sizes_as_words - bool(no),
record_term_sizes_as_cells - bool(yes)], no).
% Trailing components
grade_component_table("tr", trail, [use_trail - bool(yes)], no).
% Tag reservation components
grade_component_table("rt", tag, [reserve_tag - bool(yes)], no).
% Mimimal model tabling components
grade_component_table("mm", minimal_model, [use_minimal_model - bool(yes)], no).
% Pic reg components
grade_component_table("picreg", pic, [pic_reg - bool(yes)], no).
% Debugging/Tracing components
grade_component_table("decldebug", trace,
[stack_trace - bool(yes), require_tracing - bool(yes),
decl_debug - bool(yes)], no).
grade_component_table("debug", trace,
[stack_trace - bool(yes), require_tracing - bool(yes),
decl_debug - bool(no)], no).
grade_component_table("trace", trace,
[stack_trace - bool(no), require_tracing - bool(yes),
decl_debug - bool(no)], no).
grade_component_table("strce", trace,
[stack_trace - bool(yes), require_tracing - bool(no),
decl_debug - bool(no)], no).
:- pred reset_grade_options(option_table, option_table).
:- mode reset_grade_options(in, out) is det.
reset_grade_options(Options0, Options) :-
aggregate(grade_start_values,
(pred(Pair::in, Opts0::in, Opts::out) is det :-
Pair = Option - Value,
map__set(Opts0, Option, Value, Opts)
), Options0, Options).
:- pred grade_start_values(pair(option, option_data)).
:- mode grade_start_values(out) is multi.
grade_start_values(asm_labels - bool(no)).
grade_start_values(gcc_non_local_gotos - bool(no)).
grade_start_values(gcc_global_registers - bool(no)).
grade_start_values(highlevel_code - bool(no)).
grade_start_values(highlevel_data - bool(no)).
grade_start_values(gcc_nested_functions - bool(no)).
grade_start_values(parallel - bool(no)).
grade_start_values(gc - string("none")).
grade_start_values(profile_deep - bool(no)).
grade_start_values(profile_time - bool(no)).
grade_start_values(profile_calls - bool(no)).
grade_start_values(profile_memory - bool(no)).
grade_start_values(use_trail - bool(no)).
grade_start_values(reserve_tag - bool(no)).
grade_start_values(use_minimal_model - bool(no)).
grade_start_values(pic_reg - bool(no)).
grade_start_values(stack_trace - bool(no)).
grade_start_values(require_tracing - bool(no)).
grade_start_values(decl_debug - bool(no)).
:- pred split_grade_string(string, list(string)).
:- mode split_grade_string(in, out) is semidet.
split_grade_string(GradeStr, Components) :-
string__to_char_list(GradeStr, Chars),
split_grade_string_2(Chars, Components).
:- pred split_grade_string_2(list(char), list(string)).
:- mode split_grade_string_2(in, out) is semidet.
split_grade_string_2([], []).
split_grade_string_2(Chars, Components) :-
Chars = [_|_],
list__takewhile(char_is_not('.'), Chars, ThisChars, RestChars0),
string__from_char_list(ThisChars, ThisComponent),
Components = [ThisComponent|RestComponents],
(
RestChars0 = [_|RestChars], % discard the `.'
split_grade_string_2(RestChars, RestComponents)
;
RestChars0 = [],
RestComponents = []
).
:- pred char_is_not(char, char).
:- mode char_is_not(in, in) is semidet.
char_is_not(A, B) :-
A \= B.
%-----------------------------------------------------------------------------%
% This predicate converts a symbolic name for a set of verbosity options
% (a "dump alias") into the string consisting of those options' characters.
%
% The meanings of the option characters are documented by doc/user_guide.texi
% and by compiler/hlds_out.m. The latter is more authoritative :-)
%
% You are welcome to add more aliases.
:- pred convert_dump_alias(string, string).
:- mode convert_dump_alias(in, out) is semidet.
convert_dump_alias("ALL", "abcdfgilmnprstuvCDIMPTU").
convert_dump_alias("all", "abcdfgilmnprstuvCMPT").
convert_dump_alias("most", "bcdfgilmnprstuvP").
convert_dump_alias("trans", "bcdglmnstuv").
convert_dump_alias("codegen", "dfnprsu").
convert_dump_alias("vanessa", "ltuCIU").
convert_dump_alias("paths", "cP").
convert_dump_alias("petdr", "din").
convert_dump_alias("osv", "bcdglmnpruvP"). % for debugging
% --optimize-saved-vars-cell