#!/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; }