Files
mercury/tools/make_optimization_options_middle
Zoltan Somogyi 7c296404bb Add "Opt level N automatically sets --xyz" ...
... to the user guide entries of the affected optimization options.

compiler/print_help.m:
    Implement the above.

doc/user_guide.texi:
    Expect the additions, both from this diff, and earlier ones.

tools/make_optimization_options_middle:
compiler/optimization_options.m:
    To make the above slightly simpler to implement, add a subtype
    of the option_data type, and change the type of the predicate
    that returns the options enabled at each optimization level
    to use this subtype.

configure.ac:
    Require the installed compiler to support the fix without which
    the subtype definition would make the automatically-generated
    contents of libs.optimization_options.int2 invalid.
2025-07-08 16:38:08 +02:00

458 lines
19 KiB
Awk
Executable File

#!/usr/bin/awk -f
# vim: ts=4 sw=4 et ft=awk
#---------------------------------------------------------------------------#
# Copyright (C) 2020, 2025 The Mercury team.
# This file may only be copied under the terms of the GNU General
# Public License - see the file COPYING in the Mercury distribution.
#---------------------------------------------------------------------------#
#
# The input to this file, make_optimization_options_db, has one line
# for every optimization option. Each line must have either three
# or four fields.
#
# - The first field indicates what kind of option this is. It must be
# one of "bool", "int" and "string".
#
# - The second field gives the initial value of the option.
#
# - If the option is boolean, the initial value must be either "n" or "y".
#
# - If the option is an integer, the initial value must be an integer.
#
# - If the option is a string, the initial value will be set
# to the empty string regardless of the contents of the second field.
#
# - The third field is the name of the option in options.m.
#
# - The fourth field, if it exists, gives the name of the option
# in the file this script helps generate, optimization_options.m.
# If there is no fourth field, the name is taken to be the same
# as the name in the third field.
#
# For boolean options, the name in make_optimization_options_db should be
# a verb, because when we generate a bespoke type for it, its two function
# symbols will be named "verb" and "do_not_verb".
#
BEGIN {
next_bool_opt = 0;
next_int_opt = 0;
next_string_opt = 0;
next_bool_n_opt = 0;
next_bool_y_opt = 0;
}
{
if (NF == 3 || NF == 4) {
kind = $1;
initial_value = $2;
option_name = $3;
if (NF == 4) {
option_field_name = $4;
} else {
option_field_name = $3;
}
if (kind == "bool") {
bool_opts[next_bool_opt] = option_name;
bool_field_names[next_bool_opt] = option_field_name;
if (initial_value == "y") {
bool_defaults[next_bool_opt] = option_field_name;
bool_y_opts[next_bool_y_opt] = option_name;
next_bool_y_opt++;
} else if (initial_value == "n") {
bool_defaults[next_bool_opt] = "do_not_" option_field_name;
bool_n_opts[next_bool_n_opt] = option_name;
next_bool_n_opt++;
} else {
printf("ERROR: bad bool default <%s>\n", $0);
}
bool_initial_value[next_bool_opt] = initial_value;
next_bool_opt++;
} else if (kind == "int") {
int_opts[next_int_opt] = $3;
int_field_names[next_int_opt] = option_field_name;
int_defaults[next_int_opt] = initial_value + 0;
next_int_opt++;
} else if (kind == "string") {
string_opts[next_string_opt] = $3;
string_field_names[next_string_opt] = option_field_name;
# String options are always initialized to the empty string.
# To avoid this messing up awk's field counting, we require
# a dash to fill in the black.
if (initial_value == "-") {
string_defaults[next_int_opt] = "";
} else {
printf("ERROR: bad string default <%s>\n", $0);
}
next_string_opt++;
} else {
printf("ERROR: line with unknown type: <%s>\n", $0);
}
} else {
printf("ERROR: line with %d fields: <%s>\n", NF, $0);
}
}
END {
doc_switch_type_name = "documented_optimization_option";
doc_switch_type_functor_name = "doc_oo";
switch_type_name = "optimization_option";
doc_switch_var_name = "DocOptOption";
switch_var_name = "OptOption";
record_type_name = "opt_tuple";
record_var_name = "OptTuple";
for (i = 0; i < next_bool_opt; i++) {
printf(":- type maybe_%s\n", bool_field_names[i]);
printf(" ---> %s\n", bool_field_names[i]);
printf(" ; do_not_%s.\n", bool_field_names[i]);
}
printf("\n%%---------------------%%\n\n");
printf(":- type %s\n", switch_type_name);
for (i = 0; i < next_bool_opt; i++) {
prefix=";";
suffix="";
if (i == 0)
prefix = "--->";
printf("%-4s%-4s%-4soo_%s(bool)%s\n",
"", prefix, "", bool_field_names[i], suffix);
}
for (i = 0; i < next_int_opt; i++) {
prefix=";";
suffix="";
printf("%-4s%-4s%-4soo_%s(int)%s\n", "",
prefix, "", int_field_names[i], suffix);
}
for (i = 0; i < next_string_opt; i++) {
prefix=";";
suffix="";
printf("%-4s%-4s%-4soo_%s(string)%s\n",
"", prefix, "", string_field_names[i], suffix);
}
printf("%-4s%-4s%-4soo_opt_level(int)\n", "", prefix, "");
printf("%-4s%-4s%-4soo_opt_for_space.\n", "", prefix, "");
printf("\n%%---------------------%%\n\n");
printf(":- type %s\n", record_type_name);
printf("%-4s--->%-4s%s(\n", "", "", record_type_name);
for (i = 0; i < next_bool_opt; i++) {
suffix = ",";
printf("%-16sot_%-26s :: maybe_%s%s\n",
"", bool_field_names[i], bool_field_names[i], suffix);
}
for (i = 0; i < next_int_opt; i++) {
suffix = ",";
printf("%-16sot_%-26s :: int%s\n", "", int_field_names[i], suffix);
}
for (i = 0; i < next_string_opt; i++) {
suffix = ",";
if (i == next_string_opt-1)
suffix = "";
printf("%-16sot_%-26s :: string%s\n",
"", string_field_names[i], suffix);
}
printf("%-12s).\n", "");
# Put this predicate first, even though it is the least important
# exported predicate here and should therefore come last. The reason
# for that is that opts_enabled_at_level is not generated here.
# Instead, it is defined in make_optimization_options_db_end,
# which *guarantees* that it will come after any predicate defined
# by the output of this script. We put this predicate at the front
# to avoid putting it in the middle of a related-to-each-other
# predicates.
printf("\n");
printf(":- pred bool_option_initial_n_y(%s::out, %s::out) is det.\n",
"list(option)", "list(option)");
printf("\n");
printf(":- pred process_optimization_options(option_table::in,\n");
printf("%-4slist(%s)::in, %s::out) is det.\n",
"", switch_type_name, record_type_name);
printf("\n");
printf(":- type %s\n", doc_switch_type_name);
printf("%-4s--->%-4s%s(\n", "", "", doc_switch_type_functor_name);
printf("%-16s%s,\n", "", switch_type_name);
printf("%-16soption,\n", "");
printf("%-16soption_data_bool_int\n", "");
printf("%-12s).\n", "");
printf("\n");
printf(":- type option_data_bool_int =< option_data\n");
printf("%-4s--->%-4s%s\n", "", "", "bool(bool)");
printf("%-4s;%-7s%s\n", "", "", "int(int).");
printf("\n");
printf(":- pred opts_enabled_at_level(int::in, list(string)::out,\n");
printf("%-4slist(%s)::out) is semidet.\n", "", doc_switch_type_name);
printf("\n");
printf("%%---------------------------------------------------------------------------%%\n");
printf("\n");
printf(":- implementation.\n");
printf("\n");
printf(":- import_module int.\n");
printf(":- import_module map.\n");
printf(":- import_module string.\n");
printf("\n%%---------------------%%\n");
printf("\n");
printf("bool_option_initial_n_y(No, Yes) :-\n");
printf("%-4sNo = [\n", "");
for (i = 0; i < next_bool_n_opt; i++) {
suffix = ",";
if (i == next_bool_n_opt-1) {
suffix = "";
}
printf("%-8soptopt_%s%s\n", "", bool_n_opts[i], suffix);
}
printf("%-4s],\n", "");
printf("%-4sYes = [\n", "");
for (i = 0; i < next_bool_y_opt; i++) {
suffix = ",";
if (i == next_bool_y_opt-1) {
suffix = "";
}
printf("%-8soptopt_%s%s\n", "", bool_y_opts[i], suffix);
}
printf("%-4s].\n", "");
printf("\n%%---------------------%%\n\n");
printf("process_optimization_options(OptionTable, OptOptions, !:OptTuple) :-\n");
printf("%-4s!:OptTuple = init_opt_tuple,\n", "");
printf("%-4slist.foldl2(\n", "");
printf("%-8supdate_opt_tuple(not_from_opt_level, OptionTable),\n", "");
printf("%-8sOptOptions, !OptTuple, not_seen_opt_level, MaybeSeenOptLevel),\n", "");
printf("%-4s(\n", "");
printf("%-8sMaybeSeenOptLevel = not_seen_opt_level,\n", "");
printf("%-8sget_default_opt_level(OptionTable, DefaultOptLevel),\n", "");
printf("%-8sset_opts_upto_level(OptionTable, 0, DefaultOptLevel,\n",
"");
printf("%-12s!OptTuple, MaybeSeenOptLevel, _)\n", "");
printf("%-4s;\n", "");
printf("%-8sMaybeSeenOptLevel = seen_opt_level\n", "");
printf("%-4s).\n", "");
printf("\n%%---------------------%%\n");
printf("\n");
printf(":- func init_opt_tuple = %s.\n\n", record_type_name);
printf("init_opt_tuple =\n");
printf("%-4s%s(\n", "", record_type_name);
for (i = 0; i < next_bool_opt; i++) {
printf("%-8s%s,\n", "", bool_defaults[i]);
}
for (i = 0; i < next_int_opt; i++) {
printf("%-8s%s,\n", "", int_defaults[i]);
}
for (i = 0; i < next_string_opt; i++) {
suffix = ",";
if (i == next_string_opt-1) {
suffix = "";
}
printf("%-8s%s%s\n", "", "\"\"", suffix);
}
printf("%-4s).\n", "");
printf("\n%%---------------------%%\n");
printf("\n");
printf(":- type maybe_seen_opt_level\n");
printf("%-4s%-8snot_seen_opt_level\n", "", "--->");
printf("%-4s%-8sseen_opt_level.\n", "", ";");
printf("\n");
printf(":- type maybe_from_opt_level\n");
printf("%-4s%-8snot_from_opt_level\n", "", "--->");
printf("%-4s%-8sfrom_opt_level.\n", "", ";");
printf("\n");
printf(":- pred update_opt_tuple(maybe_from_opt_level::in, ");
printf("option_table::in,\n");
printf("%-4s%s::in, %s::in, %s::out,\n",
"", switch_type_name, record_type_name, record_type_name);
printf("%-4smaybe_seen_opt_level::in, maybe_seen_opt_level::out) is det.\n", "");
printf("\n");
# Each arm of the switch that handles an ordinary bool or int option
# forwards its work to a separate tiny predicate. We used to generate
# inline code for them, but this led to the Java bytecode generated
# for update_opt_tuple to exceed the 64k limit on the size of a single
# method. This was Mantis bug #522.
printf("update_opt_tuple(FromOptLevel, OptionTable, %s, !%s,\n",
switch_var_name, record_var_name);
printf("%-8s!MaybeSeenOptLevel) :-\n",
"", switch_var_name, record_var_name);
printf("%-4srequire_complete_switch [%s]\n", "", switch_var_name);
lparen_or_semi = "(";
for (i = 0; i < next_bool_opt; i++) {
printf("%-4s%s\n", "", lparen_or_semi);
lparen_or_semi = ";";
printf("%-8s%s = oo_%s(Bool),\n", "",
switch_var_name, bool_field_names[i]);
if (bool_field_names[i] == "opt_delay_slot") {
printf("%-8supdate_opt_tuple_bool_%s(OptionTable, Bool, !%s)\n",
"", bool_field_names[i], record_var_name);
} else {
printf("%-8supdate_opt_tuple_bool_%s(Bool, !%s)\n",
"", bool_field_names[i], record_var_name);
}
}
for (i = 0; i < next_int_opt; i++) {
printf("%-4s%s\n", "", lparen_or_semi);
lparen_or_semi = ";";
printf("%-8s%s = oo_%s(N),\n",
"", switch_var_name, int_field_names[i]);
printf("%-8supdate_opt_tuple_int_%s(FromOptLevel, N, !%s)\n",
"", int_field_names[i], record_var_name);
}
for (i = 0; i < next_string_opt; i++) {
printf("%-4s%s\n", "", lparen_or_semi);
lparen_or_semi = ";";
printf("%-8s%s = oo_%s(Str),\n",
"", switch_var_name, string_field_names[i]);
printf("%-8s!%s ^ ot_%s := Str\n",
"", record_var_name, string_field_names[i]);
}
printf("%-4s%s\n", "", lparen_or_semi);
lparen_or_semi = ";";
printf("%-8s%s = oo_opt_level(OptLevel),\n", "", switch_var_name);
printf("%-8sset_opts_upto_level(OptionTable, 0, OptLevel, !%s, !.MaybeSeenOptLevel, _),\n",
"", record_var_name);
printf("%-8s!:MaybeSeenOptLevel = seen_opt_level\n", "");
printf("%-4s%s\n", "", lparen_or_semi);
printf("%-8s%s = oo_opt_for_space,\n", "", switch_var_name);
printf("%-8sset_opts_for_space(!%s)\n", "", record_var_name);
printf("%-4s).\n\n", "");
for (i = 0; i < next_bool_opt; i++) {
if (bool_field_names[i] == "opt_delay_slot") {
printf(":- pred update_opt_tuple_bool_%s(",
bool_field_names[i]);
printf("option_table::in, bool::in,\n");
printf("%-4s%s::in, %s::out) is det.\n\n",
"", record_type_name, record_type_name);
printf("update_opt_tuple_bool_%s(OptionTable, Bool, !%s) :-\n",
bool_field_names[i], record_var_name);
} else {
printf(":- pred update_opt_tuple_bool_%s(",
bool_field_names[i]);
printf("bool::in,\n");
printf("%-4s%s::in, %s::out) is det.\n\n",
"", record_type_name, record_type_name);
printf("update_opt_tuple_bool_%s(Bool, !%s) :-\n",
bool_field_names[i], record_var_name);
}
printf("%-4sOldValue = !.%s ^ ot_%s,\n",
"", record_var_name, bool_field_names[i]);
printf("%-4s( if\n", "");
if (bool_field_names[i] == "opt_delay_slot") {
printf("%-8sgetopt.lookup_bool_option(OptionTable, have_delay_slot, yes),\n",
"");
}
printf("%-8sBool = yes\n", "");
printf("%-4sthen\n", "");
printf("%-8s(\n", "");
printf("%-12sOldValue = do_not_%s,\n", "", bool_field_names[i]);
printf("%-12s!%s ^ ot_%s := %s\n",
"", record_var_name, bool_field_names[i], bool_field_names[i]);
printf("%-8s;\n", "");
printf("%-12sOldValue = %s\n", "", bool_field_names[i]);
printf("%-8s)\n", "");
printf("%-4selse\n", "");
printf("%-8s(\n", "");
printf("%-12sOldValue = do_not_%s\n", "", bool_field_names[i]);
printf("%-8s;\n", "");
printf("%-12sOldValue = %s,\n", "", bool_field_names[i]);
printf("%-12s!%s ^ ot_%s := do_not_%s\n",
"", record_var_name, bool_field_names[i], bool_field_names[i]);
printf("%-8s)\n", "");
printf("%-4s).\n\n", "");
}
for (i = 0; i < next_int_opt; i++) {
printf(":- pred update_opt_tuple_int_%s(\n",
int_field_names[i]);
printf("%-4smaybe_from_opt_level::in, int::in,\n", "");
printf("%-4s%s::in, %s::out) is det.\n\n",
"", record_type_name, record_type_name);
printf("update_opt_tuple_int_%s(FromOptLevel, N, !%s) :-\n",
int_field_names[i], record_var_name);
printf("%-4s(\n", "");
printf("%-8sFromOptLevel = not_from_opt_level,\n", "");
printf("%-8s!%s ^ ot_%s := N\n",
"", record_var_name, int_field_names[i]);
printf("%-4s;\n", "");
printf("%-8sFromOptLevel = from_opt_level,\n", "");
printf("%-8sOldN = !.%s ^ ot_%s,\n",
"", record_var_name, int_field_names[i]);
printf("%-8s!%s ^ ot_%s := int.max(OldN, N)\n",
"", record_var_name, int_field_names[i]);
printf("%-4s).\n\n", "");
}
###################################################################
# The code from here to the end of the script generates code that
# should be included in the special_handler predicate in options.m.
handler_file = "handler_file";
arm_start = "(";
for (i = 0; i < next_bool_opt; i++) {
printf("%-8s%s\n", "", arm_start) > handler_file;
arm_start = ";";
printf("%-12sOption = optopt_%s,\n",
"", bool_opts[i]) > handler_file;
printf("%-12sSpecialData = bool(Bool),\n", "") > handler_file;
printf("%-12sOptOption = oo_%s(Bool)\n",
"", bool_field_names[i]) > handler_file;
}
for (i = 0; i < next_int_opt; i++) {
printf("%-8s;\n", "") > handler_file;
printf("%-12sOption = optopt_%s,\n",
"", int_opts[i]) > handler_file;
printf("%-12sSpecialData = int(N),\n", "") > handler_file;
printf("%-12sOptOption = oo_%s(N)\n",
"", int_field_names[i]) > handler_file;
}
for (i = 0; i < next_string_opt; i++) {
printf("%-8s;\n", "") > handler_file;
printf("%-12sOption = optopt_%s,\n",
"", string_opts[i]) > handler_file;
printf("%-12sSpecialData = string(Str),\n", "") > handler_file;
printf("%-12sOptOption = oo_%s(Str)\n",
"", string_field_names[i]) > handler_file;
}
printf("%-8s;\n", "") > handler_file;
printf("%-12sOption = opt_level,\n", "") > handler_file;
printf("%-12sSpecialData = int(N),\n", "") > handler_file;
printf("%-12sOptOption = oo_opt_level(N)\n", "") > handler_file;
printf("%-8s;\n", "") > handler_file;
printf("%-12sOption = opt_space,\n", "") > handler_file;
printf("%-12sSpecialData = none,\n", "") > handler_file;
printf("%-12sOptOption = oo_opt_for_space\n", "") > handler_file;
printf("%-8s),\n", "") > handler_file;
}