Generic .opt support for enumerated option arguments

Richard Guenther richard.guenther@gmail.com
Sat Nov 27 07:54:00 GMT 2010


On Fri, Nov 26, 2010 at 11:13 PM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> This patch adds generic .opt support for options whose arguments come
> from some enumerated set of strings.  Such options may now be marked
> with Enum, and optionally Var to cause the generic option-processing
> machinery to set a gcc_options field directly for the option; this is
> accompanied by Enum and EnumValue entries to define the sets of option
> arguments.
>
> The opts.c options - apart from -fstack-check=, which is pending
> review of <http://gcc.gnu.org/ml/gcc-patches/2010-11/msg02483.html> -
> are converted to the new mechanism where they take such enumerated
> arguments.  This means six options no longer need any special code
> there, and one option just needs to set a diagnostic context field in
> its code without first decoding strings.
>
> If an invalid option argument is passed to such an option, generic
> code will produce an error (some existing options used warnings, but I
> think always using errors is appropriate, just like for unknown
> options) and an informative note listing the valid arguments.
>
> The --help code can report current values of these options with -Q
> --help, and can also report the sets of possible values for such
> options.  The latter isn't currently enabled for any option because
> the common options already have the list of possible values in the
> help text for the individual options.  I have however tested it, and
> it will be useful for options such as -march= (where it will allow
> removing the TARGET_HELP hook once ARM has been converted to the new
> system; notice incidentally that TARGET_HELP only gets called for
> --target-help, not for --help=target which is supposed to mean the
> same thing or any other --help variant).
>
> Bootstrapped with no regressions on x86_64-unknown-linux-gnu.  OK to
> commit?

Ok.

Thanks,
Richard.

> 2010-11-26  Joseph Myers  <joseph@codesourcery.com>
>
>        * doc/options.texi (Enum, EnumValue): Document new record types.
>        (Enum): Document new option flag.
>        * opt-functions.awk
>        * optc-gen.awk: Handle enumerated option arguments.
>        * opth-gen.awk: Handle enumerated option arguments.
>        * opts-common.c (enum_arg_ok_for_language, enum_arg_to_value,
>        enum_value_to_arg): New.
>        (decode_cmdline_option): Handle enumerated arguments.
>        (read_cmdline_option): Handle CL_ERR_ENUM_ARG.
>        (set_option, option_enabled, get_option_state): Handle CLVC_ENUM.
>        * opts.c (print_filtered_help, print_specific_help): Take
>        lang_mask arguments.
>        (print_filtered_help): Handle printing values of enumerated
>        options.  Print possible arguments for enumerated options.
>        (print_specific_help): Update call to print_filtered_help.
>        (common_handle_option): Update calls to print_specific_help.  Use
>        value rather than arg for OPT_fdiagnostics_show_location_.  Don't
>        handle OPT_ffp_contract_, OPT_fexcess_precision_,
>        OPT_fvisibility_, OPT_ftls_model_, OPT_fira_algorithm_ or
>        OPT_fira_region_ here.
>        * opts.h (enum cl_var_type): Add CLVC_ENUM.
>        (struct cl_option): Add var_enum.
>        (CL_ENUM_CANONICAL, CL_ENUM_DRIVER_ONLY, struct cl_enum_arg,
>        struct cl_enum, cl_enums, cl_enums_count): New.
>        (CL_ERR_ENUM_ARG): Define.
>        (CL_ERR_NEGATIVE): Update value.
>        (enum_value_to_arg): Declare.
>        * common.opt (flag_ira_algorithm, flag_ira_region,
>        flag_fp_contract_mode, flag_excess_precision_cmdline,
>        default_visibility, flag_tls_default): Remove Variable entries.
>        (help_enum_printed): New Variable.
>        (fdiagnostics-show-location=): Use Enum.  Add associated
>        SourceInclude, Enum and EnumValue entries.
>        (fexcess-precision=, ffp-contract=, fira-algorithm=, fira-region=,
>        ftls-model=, fvisibility=): Use Enum, Var and Init.  Add
>        associated Enum and EnumValue entries.
>
> po:
> 2010-11-26  Joseph Myers  <joseph@codesourcery.com>
>
>        * exgettext: Handle UnknownError.
>
> Index: gcc/doc/options.texi
> ===================================================================
> --- gcc/doc/options.texi        (revision 167145)
> +++ gcc/doc/options.texi        (working copy)
> @@ -78,6 +78,63 @@ two fields: the string @samp{SourceInclu
>  include file.
>
>  @item
> +An enumeration record to define a set of strings that may be used as
> +arguments to an option or options.  These records have three fields:
> +the string @samp{Enum}, a space-separated list of properties and help
> +text used to describe the set of strings in @option{--help} output.
> +Properties use the same format as option properties; the following are
> +valid:
> +@table @code
> +@item Name(@var{name})
> +This property is required; @var{name} must be a name (suitable for use
> +in C identifiers) used to identify the set of strings in @code{Enum}
> +option properties.
> +
> +@item Type(@var{type})
> +This property is required; @var{type} is the C type for variables set
> +by options using this enumeration together with @code{Var}.
> +
> +@item UnknownError(@var{message})
> +The message @var{message} will be used as an error message if the
> +argument is invalid; for enumerations without @code{UnknownError}, a
> +generic error message is used.  @var{message} should contain a single
> +@samp{%qs} format, which will be used to format the invalid argument.
> +@end table
> +
> +@item
> +An enumeration value record to define one of the strings in a set
> +given in an @samp{Enum} record.  These records have two fields: the
> +string @samp{EnumValue} and a space-separated list of properties.
> +Properties use the same format as option properties; the following are
> +valid:
> +@table @code
> +@item Enum(@var{name})
> +This property is required; @var{name} says which @samp{Enum} record
> +this @samp{EnumValue} record corresponds to.
> +
> +@item String(@var{string})
> +This property is required; @var{string} is the string option argument
> +being described by this record.
> +
> +@item Value(@var{value})
> +This property is required; it says what value (representable as
> +@code{int}) should be used for the given string.
> +
> +@item Canonical
> +This property is optional.  If present, it says the present string is
> +the canonical one among all those with the given value.  Other strings
> +yielding that value will be mapped to this one so specs do not need to
> +handle them.
> +
> +@item DriverOnly
> +This property is optional.  If present, the present string will only
> +be accepted by the driver.  This is used for cases such as
> +@option{-march=native} that are processed by the driver so that
> +@samp{gcc -v} shows how the options chosen depended on the system on
> +which the compiler was run.
> +@end table
> +
> +@item
>  An option definition record.  These records have the following fields:
>  @enumerate
>  @item
> @@ -227,6 +284,13 @@ If the option takes an argument and has
>  @var{var} is an integer variable that stores the value of the argument.
>
>  @item
> +If the option takes an argument and has the @code{Enum} property,
> +@var{var} is a variable (type given in the @code{Type} property of the
> +@samp{Enum} record whose @code{Name} property has the same argument as
> +the @code{Enum} property of this option) that stores the value of the
> +argument.
> +
> +@item
>  If the option has the @code{Defer} property, @var{var} is a pointer to
>  a @code{VEC(cl_deferred_option,heap)} that stores the option for later
>  processing.  (@var{var} is declared with type @code{void *} and needs
> @@ -287,6 +351,12 @@ The main purpose of this property is to
>  The first option should use @samp{Mask(@var{name})} and the others
>  should use @samp{Mask(@var{name}) MaskExists}.
>
> +@item Enum(@var{name})
> +The option's argument is a string from the set of strings associated
> +with the corresponding @samp{Enum} record.  The string is checked and
> +converted to the integer specified in the corresponding
> +@samp{EnumValue} record before being passed to option handlers.
> +
>  @item Defer
>  The option should be stored in a vector, specified with @code{Var},
>  for later processing.
> Index: gcc/opts-common.c
> ===================================================================
> --- gcc/opts-common.c   (revision 167145)
> +++ gcc/opts-common.c   (working copy)
> @@ -181,6 +181,70 @@ option_ok_for_language (const struct cl_
>   return true;
>  }
>
> +/* Return whether ENUM_ARG is OK for the language given by
> +   LANG_MASK.  */
> +
> +static bool
> +enum_arg_ok_for_language (const struct cl_enum_arg *enum_arg,
> +                         unsigned int lang_mask)
> +{
> +  return (lang_mask & CL_DRIVER) || !(enum_arg->flags & CL_ENUM_DRIVER_ONLY);
> +}
> +
> +/* Look up ARG in ENUM_ARGS for language LANG_MASK, returning true and
> +   storing the value in *VALUE if found, and returning false without
> +   modifying *VALUE if not found.  */
> +
> +static bool
> +enum_arg_to_value (const struct cl_enum_arg *enum_args,
> +                  const char *arg, int *value, unsigned int lang_mask)
> +{
> +  unsigned int i;
> +
> +  for (i = 0; enum_args[i].arg != NULL; i++)
> +    if (strcmp (arg, enum_args[i].arg) == 0
> +       && enum_arg_ok_for_language (&enum_args[i], lang_mask))
> +      {
> +       *value = enum_args[i].value;
> +       return true;
> +      }
> +
> +  return false;
> +}
> +
> +/* Look of VALUE in ENUM_ARGS for language LANG_MASK and store the
> +   corresponding string in *ARGP, returning true if the found string
> +   was marked as canonical, false otherwise.  If VALUE is not found
> +   (which may be the case for uninitialized values if the relevant
> +   option has not been passed), set *ARGP to NULL and return
> +   false.  */
> +
> +bool
> +enum_value_to_arg (const struct cl_enum_arg *enum_args,
> +                  const char **argp, int value, unsigned int lang_mask)
> +{
> +  unsigned int i;
> +
> +  for (i = 0; enum_args[i].arg != NULL; i++)
> +    if (enum_args[i].value == value
> +       && (enum_args[i].flags & CL_ENUM_CANONICAL)
> +       && enum_arg_ok_for_language (&enum_args[i], lang_mask))
> +      {
> +       *argp = enum_args[i].arg;
> +       return true;
> +      }
> +
> +  for (i = 0; enum_args[i].arg != NULL; i++)
> +    if (enum_args[i].value == value
> +       && enum_arg_ok_for_language (&enum_args[i], lang_mask))
> +      {
> +       *argp = enum_args[i].arg;
> +       return false;
> +      }
> +
> +  *argp = NULL;
> +  return false;
> +}
>
>  /* Fill in the canonical option part of *DECODED with an option
>    described by OPT_INDEX, ARG and VALUE.  */
> @@ -508,6 +572,24 @@ decode_cmdline_option (const char **argv
>        errors |= CL_ERR_UINT_ARG;
>     }
>
> +  /* If the switch takes an enumerated argument, convert it.  */
> +  if (arg && (option->var_type == CLVC_ENUM))
> +    {
> +      const struct cl_enum *e = &cl_enums[option->var_enum];
> +
> +      gcc_assert (value == 1);
> +      if (enum_arg_to_value (e->values, arg, &value, lang_mask))
> +       {
> +         const char *carg = NULL;
> +
> +         if (enum_value_to_arg (e->values, &carg, value, lang_mask))
> +           arg = carg;
> +         gcc_assert (carg != NULL);
> +       }
> +      else
> +       errors |= CL_ERR_ENUM_ARG;
> +    }
> +
>  done:
>   decoded->opt_index = opt_index;
>   decoded->arg = arg;
> @@ -900,6 +982,36 @@ read_cmdline_option (struct gcc_options
>       return;
>     }
>
> +  if (decoded->errors & CL_ERR_ENUM_ARG)
> +    {
> +      const struct cl_enum *e = &cl_enums[option->var_enum];
> +      unsigned int i;
> +      size_t len;
> +      char *s, *p;
> +
> +      if (e->unknown_error)
> +       error_at (loc, e->unknown_error, decoded->arg);
> +      else
> +       error_at (loc, "unrecognized argument in option %qs", opt);
> +
> +      len = 0;
> +      for (i = 0; e->values[i].arg != NULL; i++)
> +       len += strlen (e->values[i].arg) + 1;
> +
> +      s = XALLOCAVEC (char, len);
> +      p = s;
> +      for (i = 0; e->values[i].arg != NULL; i++)
> +       {
> +         size_t arglen = strlen (e->values[i].arg);
> +         memcpy (p, e->values[i].arg, arglen);
> +         p[arglen] = ' ';
> +         p += arglen + 1;
> +       }
> +      p[-1] = 0;
> +      inform (loc, "valid arguments to %qs are: %s", option->opt_text, s);
> +      return;
> +    }
> +
>   gcc_assert (!decoded->errors);
>
>   if (!handle_option (opts, opts_set, decoded, lang_mask, DK_UNSPECIFIED,
> @@ -959,6 +1071,16 @@ set_option (struct gcc_options *opts, st
>          *(const char **) set_flag_var = "";
>        break;
>
> +    case CLVC_ENUM:
> +      {
> +       const struct cl_enum *e = &cl_enums[option->var_enum];
> +
> +       e->set (flag_var, value);
> +       if (set_flag_var)
> +         e->set (set_flag_var, 1);
> +      }
> +      break;
> +
>     case CLVC_DEFER:
>        {
>          VEC(cl_deferred_option,heap) *vec
> @@ -1020,6 +1142,7 @@ option_enabled (int opt_idx, void *opts)
>        return (*(int *) flag_var & option->var_value) != 0;
>
>       case CLVC_STRING:
> +      case CLVC_ENUM:
>       case CLVC_DEFER:
>        break;
>       }
> @@ -1060,6 +1183,11 @@ get_option_state (struct gcc_options *op
>       state->size = strlen ((const char *) state->data) + 1;
>       break;
>
> +    case CLVC_ENUM:
> +      state->data = flag_var;
> +      state->size = cl_enums[cl_options[option].var_enum].var_size;
> +      break;
> +
>     case CLVC_DEFER:
>       return false;
>     }
> Index: gcc/opts.c
> ===================================================================
> --- gcc/opts.c  (revision 167145)
> +++ gcc/opts.c  (working copy)
> @@ -885,7 +885,8 @@ print_filtered_help (unsigned int includ
>                     unsigned int exclude_flags,
>                     unsigned int any_flags,
>                     unsigned int columns,
> -                    struct gcc_options *opts)
> +                    struct gcc_options *opts,
> +                    unsigned int lang_mask)
>  {
>   unsigned int i;
>   const char *help;
> @@ -918,6 +919,9 @@ print_filtered_help (unsigned int includ
>   if (!opts->x_help_printed)
>     opts->x_help_printed = XCNEWVAR (char, cl_options_count);
>
> +  if (!opts->x_help_enum_printed)
> +    opts->x_help_enum_printed = XCNEWVAR (char, cl_enums_count);
> +
>   for (i = 0; i < cl_options_count; i++)
>     {
>       char new_help[128];
> @@ -999,6 +1003,20 @@ print_filtered_help (unsigned int includ
>                                  sizeof (new_help) - strlen (new_help),
>                                  * (const char **) flag_var);
>                    }
> +                 else if (option->var_type == CLVC_ENUM)
> +                   {
> +                     const struct cl_enum *e = &cl_enums[option->var_enum];
> +                     int value;
> +                     const char *arg = NULL;
> +
> +                     value = e->get (flag_var);
> +                     enum_value_to_arg (e->values, &arg, value, lang_mask);
> +                     if (arg == NULL)
> +                       arg = _("[default]");
> +                     snprintf (new_help + strlen (new_help),
> +                               sizeof (new_help) - strlen (new_help),
> +                               arg);
> +                   }
>                  else
>                    sprintf (new_help + strlen (new_help),
>                             "%#x", * (int *) flag_var);
> @@ -1013,6 +1031,10 @@ print_filtered_help (unsigned int includ
>
>       wrap_help (help, opt, len, columns);
>       displayed = true;
> +
> +      if (option->var_type == CLVC_ENUM
> +         && opts->x_help_enum_printed[option->var_enum] != 2)
> +       opts->x_help_enum_printed[option->var_enum] = 1;
>     }
>
>   if (! found)
> @@ -1038,18 +1060,57 @@ print_filtered_help (unsigned int includ
>     printf (_(" All options with the desired characteristics have already been displayed\n"));
>
>   putchar ('\n');
> +
> +  /* Print details of enumerated option arguments, if those
> +     enumerations have help text headings provided.  If no help text
> +     is provided, presume that the possible values are listed in the
> +     help text for the relevant options.  */
> +  for (i = 0; i < cl_enums_count; i++)
> +    {
> +      unsigned int j, pos;
> +
> +      if (opts->x_help_enum_printed[i] != 1)
> +       continue;
> +      if (cl_enums[i].help == NULL)
> +       continue;
> +      printf ("  %s\n    ", _(cl_enums[i].help));
> +      pos = 4;
> +      for (j = 0; cl_enums[i].values[j].arg != NULL; j++)
> +       {
> +         unsigned int len = strlen (cl_enums[i].values[j].arg);
> +
> +         if (pos > 4 && pos + 1 + len <= columns)
> +           {
> +             printf (" %s", cl_enums[i].values[j].arg);
> +             pos += 1 + len;
> +           }
> +         else
> +           {
> +             if (pos > 4)
> +               {
> +                 printf ("\n    ");
> +                 pos = 4;
> +               }
> +             printf ("%s", cl_enums[i].values[j].arg);
> +             pos += len;
> +           }
> +       }
> +      printf ("\n\n");
> +      opts->x_help_enum_printed[i] = 2;
> +    }
>  }
>
>  /* Display help for a specified type of option.
>    The options must have ALL of the INCLUDE_FLAGS set
>    ANY of the flags in the ANY_FLAGS set
>    and NONE of the EXCLUDE_FLAGS set.  The current option state is in
> -   OPTS.  */
> +   OPTS; LANG_MASK is used for interpreting enumerated option state.  */
>  static void
>  print_specific_help (unsigned int include_flags,
>                     unsigned int exclude_flags,
>                     unsigned int any_flags,
> -                    struct gcc_options *opts)
> +                    struct gcc_options *opts,
> +                    unsigned int lang_mask)
>  {
>   unsigned int all_langs_mask = (1U << cl_lang_count) - 1;
>   const char * description = NULL;
> @@ -1145,7 +1206,7 @@ print_specific_help (unsigned int includ
>
>   printf ("%s%s:\n", description, descrip_extra);
>   print_filtered_help (include_flags, exclude_flags, any_flags,
> -                      opts->x_help_columns, opts);
> +                      opts->x_help_columns, opts, lang_mask);
>  }
>
>  /* Handle target- and language-independent options.  Return zero to
> @@ -1187,19 +1248,20 @@ common_handle_option (struct gcc_options
>        /* First display any single language specific options.  */
>        for (i = 0; i < cl_lang_count; i++)
>          print_specific_help
> -           (1U << i, (all_langs_mask & (~ (1U << i))) | undoc_mask, 0, opts);
> +           (1U << i, (all_langs_mask & (~ (1U << i))) | undoc_mask, 0, opts,
> +            lang_mask);
>        /* Next display any multi language specific options.  */
> -       print_specific_help (0, undoc_mask, all_langs_mask, opts);
> +       print_specific_help (0, undoc_mask, all_langs_mask, opts, lang_mask);
>        /* Then display any remaining, non-language options.  */
>        for (i = CL_MIN_OPTION_CLASS; i <= CL_MAX_OPTION_CLASS; i <<= 1)
>          if (i != CL_DRIVER)
> -           print_specific_help (i, undoc_mask, 0, opts);
> +           print_specific_help (i, undoc_mask, 0, opts, lang_mask);
>        opts->x_exit_after_options = true;
>        break;
>       }
>
>     case OPT__target_help:
> -      print_specific_help (CL_TARGET, CL_UNDOCUMENTED, 0, opts);
> +      print_specific_help (CL_TARGET, CL_UNDOCUMENTED, 0, opts, lang_mask);
>       opts->x_exit_after_options = true;
>
>       /* Allow the target a chance to give the user some additional information.  */
> @@ -1321,7 +1383,8 @@ common_handle_option (struct gcc_options
>          }
>
>        if (include_flags)
> -         print_specific_help (include_flags, exclude_flags, 0, opts);
> +         print_specific_help (include_flags, exclude_flags, 0, opts,
> +                              lang_mask);
>        opts->x_exit_after_options = true;
>        break;
>       }
> @@ -1405,13 +1468,7 @@ common_handle_option (struct gcc_options
>       break;
>
>     case OPT_fdiagnostics_show_location_:
> -      if (!strcmp (arg, "once"))
> -       diagnostic_prefixing_rule (dc) = DIAGNOSTICS_SHOW_PREFIX_ONCE;
> -      else if (!strcmp (arg, "every-line"))
> -       diagnostic_prefixing_rule (dc)
> -         = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE;
> -      else
> -       return false;
> +      diagnostic_prefixing_rule (dc) = (diagnostic_prefixing_rule_t) value;
>       break;
>
>     case OPT_fdiagnostics_show_option:
> @@ -1422,27 +1479,6 @@ common_handle_option (struct gcc_options
>       /* Deferred.  */
>       break;
>
> -    case OPT_ffp_contract_:
> -      if (!strcmp (arg, "on"))
> -       /* Not implemented, fall back to conservative FP_CONTRACT_OFF.  */
> -       opts->x_flag_fp_contract_mode = FP_CONTRACT_OFF;
> -      else if (!strcmp (arg, "off"))
> -       opts->x_flag_fp_contract_mode = FP_CONTRACT_OFF;
> -      else if (!strcmp (arg, "fast"))
> -       opts->x_flag_fp_contract_mode = FP_CONTRACT_FAST;
> -      else
> -       error_at (loc, "unknown floating point contraction style \"%s\"", arg);
> -      break;
> -
> -    case OPT_fexcess_precision_:
> -      if (!strcmp (arg, "fast"))
> -       opts->x_flag_excess_precision_cmdline = EXCESS_PRECISION_FAST;
> -      else if (!strcmp (arg, "standard"))
> -       opts->x_flag_excess_precision_cmdline = EXCESS_PRECISION_STANDARD;
> -      else
> -       error_at (loc, "unknown excess precision style \"%s\"", arg);
> -      break;
> -
>     case OPT_ffast_math:
>       set_fast_math_flags (opts, value);
>       break;
> @@ -1542,21 +1578,6 @@ common_handle_option (struct gcc_options
>       dc->show_column = value;
>       break;
>
> -    case OPT_fvisibility_:
> -      {
> -        if (!strcmp(arg, "default"))
> -          opts->x_default_visibility = VISIBILITY_DEFAULT;
> -        else if (!strcmp(arg, "internal"))
> -          opts->x_default_visibility = VISIBILITY_INTERNAL;
> -        else if (!strcmp(arg, "hidden"))
> -          opts->x_default_visibility = VISIBILITY_HIDDEN;
> -        else if (!strcmp(arg, "protected"))
> -          opts->x_default_visibility = VISIBILITY_PROTECTED;
> -        else
> -          error_at (loc, "unrecognized visibility value \"%s\"", arg);
> -      }
> -      break;
> -
>     case OPT_frandom_seed:
>       /* The real switch is -fno-random-seed.  */
>       if (value)
> @@ -1621,39 +1642,6 @@ common_handle_option (struct gcc_options
>       vect_set_verbosity_level (opts, value);
>       break;
>
> -    case OPT_ftls_model_:
> -      if (!strcmp (arg, "global-dynamic"))
> -       opts->x_flag_tls_default = TLS_MODEL_GLOBAL_DYNAMIC;
> -      else if (!strcmp (arg, "local-dynamic"))
> -       opts->x_flag_tls_default = TLS_MODEL_LOCAL_DYNAMIC;
> -      else if (!strcmp (arg, "initial-exec"))
> -       opts->x_flag_tls_default = TLS_MODEL_INITIAL_EXEC;
> -      else if (!strcmp (arg, "local-exec"))
> -       opts->x_flag_tls_default = TLS_MODEL_LOCAL_EXEC;
> -      else
> -       warning_at (loc, 0, "unknown tls-model \"%s\"", arg);
> -      break;
> -
> -    case OPT_fira_algorithm_:
> -      if (!strcmp (arg, "CB"))
> -       opts->x_flag_ira_algorithm = IRA_ALGORITHM_CB;
> -      else if (!strcmp (arg, "priority"))
> -       opts->x_flag_ira_algorithm = IRA_ALGORITHM_PRIORITY;
> -      else
> -       warning_at (loc, 0, "unknown ira algorithm \"%s\"", arg);
> -      break;
> -
> -    case OPT_fira_region_:
> -      if (!strcmp (arg, "one"))
> -       opts->x_flag_ira_region = IRA_REGION_ONE;
> -      else if (!strcmp (arg, "all"))
> -       opts->x_flag_ira_region = IRA_REGION_ALL;
> -      else if (!strcmp (arg, "mixed"))
> -       opts->x_flag_ira_region = IRA_REGION_MIXED;
> -      else
> -       warning_at (loc, 0, "unknown ira region \"%s\"", arg);
> -      break;
> -
>     case OPT_g:
>       set_debug_level (NO_DEBUG, DEFAULT_GDB_EXTENSIONS, arg, opts, opts_set,
>                       loc);
> Index: gcc/opts.h
> ===================================================================
> --- gcc/opts.h  (revision 167145)
> +++ gcc/opts.h  (working copy)
> @@ -42,6 +42,10 @@ enum cl_var_type {
>      argument.  */
>   CLVC_STRING,
>
> +  /* The switch takes an enumerated argument (VAR_ENUM says what
> +     enumeration) and FLAG_VAR points to that argument.  */
> +  CLVC_ENUM,
> +
>   /* The switch should be stored in the VEC pointed to by FLAG_VAR for
>      later processing.  */
>   CLVC_DEFER
> @@ -61,6 +65,7 @@ struct cl_option
>   int neg_index;
>   unsigned int flags;
>   unsigned short flag_var_offset;
> +  unsigned short var_enum;
>   enum cl_var_type var_type;
>   int var_value;
>  };
> @@ -111,6 +116,52 @@ extern const unsigned int cl_lang_count;
>  #define CL_UINTEGER            (1 << 29) /* Argument is an integer >=0.  */
>  #define CL_UNDOCUMENTED                (1 << 30) /* Do not output with --help.  */
>
> +/* Flags for an enumerated option argument.  */
> +#define CL_ENUM_CANONICAL      (1 << 0) /* Canonical for this value.  */
> +#define CL_ENUM_DRIVER_ONLY    (1 << 1) /* Only accepted in the driver.  */
> +
> +/* Structure describing an enumerated option argument.  */
> +
> +struct cl_enum_arg
> +{
> +  /* The argument text, or NULL at the end of the array.  */
> +  const char *arg;
> +
> +  /* The corresponding integer value.  */
> +  int value;
> +
> +  /* Flags associated with this argument.  */
> +  unsigned int flags;
> +};
> +
> +/* Structure describing an enumerated set of option arguments.  */
> +
> +struct cl_enum
> +{
> +  /* Help text, or NULL if the values should not be listed in --help
> +     output.  */
> +  const char *help;
> +
> +  /* Error message for unknown arguments, or NULL to use a generic
> +     error.  */
> +  const char *unknown_error;
> +
> +  /* Array of possible values.  */
> +  const struct cl_enum_arg *values;
> +
> +  /* The size of the type used to store a value.  */
> +  size_t var_size;
> +
> +  /* Function to set a variable of this type.  */
> +  void (*set) (void *var, int value);
> +
> +  /* Function to get the value of a variable of this type.  */
> +  int (*get) (const void *var);
> +};
> +
> +extern const struct cl_enum cl_enums[];
> +extern const unsigned int cl_enums_count;
> +
>  /* Possible ways in which a command-line option may be erroneous.
>    These do not include not being known at all; an option index of
>    OPT_SPECIAL_unknown is used for that.  */
> @@ -119,7 +170,8 @@ extern const unsigned int cl_lang_count;
>  #define CL_ERR_MISSING_ARG     (1 << 1) /* Argument required but missing.  */
>  #define CL_ERR_WRONG_LANG      (1 << 2) /* Option for wrong language.  */
>  #define CL_ERR_UINT_ARG                (1 << 3) /* Bad unsigned integer argument.  */
> -#define CL_ERR_NEGATIVE                (1 << 4) /* Negative form of option
> +#define CL_ERR_ENUM_ARG                (1 << 4) /* Bad enumerated argument.  */
> +#define CL_ERR_NEGATIVE                (1 << 5) /* Negative form of option
>                                            not permitted (together
>                                            with OPT_SPECIAL_unknown).  */
>
> @@ -230,6 +282,9 @@ extern unsigned num_in_fnames;
>
>  size_t find_opt (const char *input, int lang_mask);
>  extern int integral_argument (const char *arg);
> +extern bool enum_value_to_arg (const struct cl_enum_arg *enum_args,
> +                              const char **argp, int value,
> +                              unsigned int lang_mask);
>  extern void decode_cmdline_options_to_array (unsigned int argc,
>                                             const char **argv,
>                                             unsigned int lang_mask,
> Index: gcc/optc-gen.awk
> ===================================================================
> --- gcc/optc-gen.awk    (revision 167145)
> +++ gcc/optc-gen.awk    (working copy)
> @@ -34,6 +34,7 @@ BEGIN {
>        n_extra_target_vars = 0
>        n_extra_c_includes = 0
>        n_extra_h_includes = 0
> +       n_enums = 0
>        quote = "\042"
>        comma = ","
>        FS=SUBSEP
> @@ -80,6 +81,31 @@ BEGIN {
>                else if ($1 == "SourceInclude")  {
>                        extra_c_includes[n_extra_c_includes++] = $2;
>                }
> +               else if ($1 == "Enum") {
> +                       props = $2
> +                       name = opt_args("Name", props)
> +                       type = opt_args("Type", props)
> +                       unknown_error = opt_args("UnknownError", props)
> +                       enum_names[n_enums] = name
> +                       enum_type[name] = type
> +                       enum_index[name] = n_enums
> +                       enum_unknown_error[name] = unknown_error
> +                       enum_help[name] = $3
> +                       n_enums++
> +               }
> +               else if ($1 == "EnumValue")  {
> +                       props = $2
> +                       enum_name = opt_args("Enum", props)
> +                       string = opt_args("String", props)
> +                       value = opt_args("Value", props)
> +                       val_flags = "0"
> +                       val_flags = val_flags \
> +                         test_flag("Canonical", props, "| CL_ENUM_CANONICAL") \
> +                         test_flag("DriverOnly", props, "| CL_ENUM_DRIVER_ONLY")
> +                       enum_data[enum_name] = enum_data[enum_name] \
> +                         "  { " quote string quote ", " value ", " val_flags \
> +                         " },\n"
> +               }
>                else {
>                        name = opt_args("Mask", $1)
>                        if (name == "") {
> @@ -116,6 +142,56 @@ if (n_extra_c_includes > 0) {
>        print ""
>  }
>
> +for (i = 0; i < n_enums; i++) {
> +       name = enum_names[i]
> +       type = enum_type[name]
> +       print "static const struct cl_enum_arg cl_enum_" name \
> +           "_data[] = "
> +       print "{"
> +       print enum_data[name] "  { NULL, 0, 0 }"
> +       print "};"
> +       print ""
> +       print "static void"
> +       print "cl_enum_" name "_set (void *var, int value)"
> +       print "{"
> +       print "  *((" type " *) var) = (" type ") value;"
> +       print "}"
> +       print ""
> +       print "static int"
> +       print "cl_enum_" name "_get (const void *var)"
> +       print "{"
> +       print "  return (int) *((const " type " *) var);"
> +       print "}"
> +       print ""
> +}
> +
> +print "const struct cl_enum cl_enums[] ="
> +print "{"
> +for (i = 0; i < n_enums; i++) {
> +       name = enum_names[i]
> +       ehelp = enum_help[name]
> +       if (ehelp == "")
> +               ehelp = "NULL"
> +       else
> +               ehelp = quote ehelp quote
> +       unknown_error = enum_unknown_error[name]
> +       if (unknown_error == "")
> +               unknown_error = "NULL"
> +       else
> +               unknown_error = quote unknown_error quote
> +       print "  {"
> +       print "    " ehelp ","
> +       print "    " unknown_error ","
> +       print "    cl_enum_" name "_data,"
> +       print "    sizeof (" enum_type[name] "),"
> +       print "    cl_enum_" name "_set,"
> +       print "    cl_enum_" name "_get"
> +       print "  },"
> +}
> +print "};"
> +print "const unsigned int cl_enums_count = " n_enums ";"
> +print ""
> +
>  have_save = 0;
>  if (n_extra_target_vars)
>        have_save = 1
> Index: gcc/opth-gen.awk
> ===================================================================
> --- gcc/opth-gen.awk    (revision 167145)
> +++ gcc/opth-gen.awk    (working copy)
> @@ -77,6 +77,31 @@ BEGIN {
>                else if ($1 == "SourceInclude")  {
>                        extra_c_includes[n_extra_c_includes++] = $2;
>                }
> +               else if ($1 == "Enum")  {
> +                       props = $2
> +                       name = opt_args("Name", props)
> +                       type = opt_args("Type", props)
> +                       unknown_error = opt_args("UnknownError", props)
> +                       enum_names[n_enums] = name
> +                       enum_type[name] = type
> +                       enum_index[name] = n_enums
> +                       enum_unknown_error[name] = unknown_error
> +                       enum_help[name] = $3
> +                       n_enums++
> +               }
> +               else if ($1 == "EnumValue")  {
> +                       props = $2
> +                       enum_name = opt_args("Enum", props)
> +                       string = opt_args("String", props)
> +                       value = opt_args("Value", props)
> +                       val_flags = "0"
> +                       val_flags = val_flags \
> +                         test_flag("Canonical", props, "| CL_ENUM_CANONICAL") \
> +                         test_flag("DriverOnly", props, "| CL_ENUM_DRIVER_ONLY")
> +                       enum_data[enum_name] = enum_data[enum_name] \
> +                         "  { " quote string quote ", " value ", " val_flags \
> +                         " },\n"
> +               }
>                else {
>                        name = opt_args("Mask", $1)
>                        if (name == "") {
> Index: gcc/po/exgettext
> ===================================================================
> --- gcc/po/exgettext    (revision 167145)
> +++ gcc/po/exgettext    (working copy)
> @@ -246,6 +246,17 @@ echo "scanning option files..." >&2
>                printf("#line %d \"%s\"\n", lineno, file)
>                printf("_(\"%s\")\n", line)
>            }
> +           if ((field == 1) && /UnknownError/) {
> +               line = $0
> +               sub(".*UnknownError\\(", "", line)
> +               if (line ~ "^{") {
> +                       sub("^{", "", line)
> +                       sub("}\\).*", "", line)
> +               } else
> +                       sub("\\).*", "", line)
> +               printf("#line %d \"%s\"\n", lineno, file)
> +               printf("_(\"%s\")\n", line)
> +           }
>            if ((field == 1) && /Warn\(/) {
>                line = $0
>                sub(".*Warn\\(", "", line)
> Index: gcc/common.opt
> ===================================================================
> --- gcc/common.opt      (revision 167145)
> +++ gcc/common.opt      (working copy)
> @@ -42,15 +42,6 @@ int flag_complex_method = 1
>  Variable
>  int flag_evaluation_order = 0
>
> -; Set the default region and algorithm for the integrated register
> -; allocator.
> -
> -Variable
> -enum ira_algorithm flag_ira_algorithm = IRA_ALGORITHM_CB
> -
> -Variable
> -enum ira_region flag_ira_region = IRA_REGION_MIXED
> -
>  ; Language specific warning pass for unused results.
>  Variable
>  bool flag_warn_unused_result = false
> @@ -58,15 +49,6 @@ bool flag_warn_unused_result = false
>  Variable
>  int *param_values
>
> -; Floating-point contraction mode, fast by default.
> -Variable
> -enum fp_contract_mode flag_fp_contract_mode = FP_CONTRACT_FAST
> -
> -; The excess precision specified on the command line, or defaulted by
> -; the front end.
> -Variable
> -enum excess_precision flag_excess_precision_cmdline = EXCESS_PRECISION_DEFAULT
> -
>  ; Nonzero if we should write GIMPLE bytecode for link-time optimization.
>  Variable
>  int flag_generate_lto
> @@ -97,14 +79,6 @@ int flag_gen_aux_info = 0
>  Variable
>  int flag_shlib
>
> -; The default visibility for all symbols (unless overridden).
> -Variable
> -enum symbol_visibility default_visibility = VISIBILITY_DEFAULT
> -
> -; Set to the default thread-local storage (tls) model to use.
> -Variable
> -enum tls_model flag_tls_default = TLS_MODEL_GLOBAL_DYNAMIC
> -
>  ; These two are really VEC(char_p,heap) *.
>
>  Variable
> @@ -187,6 +161,12 @@ enum graph_dump_types graph_dump_format
>  Variable
>  char *help_printed
>
> +; Which enums have been printed by --help.  0 = not printed, no
> +; relevant options seen, 1 = relevant option seen, not yet printed, 2
> +; = printed.
> +Variable
> +char *help_enum_printed
> +
>  ; The number of columns for --help output.
>  Variable
>  unsigned int help_columns
> @@ -897,9 +877,22 @@ Common Report Var(flag_delete_null_point
>  Delete useless null pointer checks
>
>  fdiagnostics-show-location=
> -Common Joined RejectNegative
> +Common Joined RejectNegative Enum(diagnostic_prefixing_rule)
>  -fdiagnostics-show-location=[once|every-line]  How often to emit source location at the beginning of line-wrapped diagnostics
>
> +; Required for these enum values.
> +SourceInclude
> +pretty-print.h
> +
> +Enum
> +Name(diagnostic_prefixing_rule) Type(int)
> +
> +EnumValue
> +Enum(diagnostic_prefixing_rule) String(once) Value(DIAGNOSTICS_SHOW_PREFIX_ONCE)
> +
> +EnumValue
> +Enum(diagnostic_prefixing_rule) String(every-line) Value(DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE)
> +
>  fdiagnostics-show-option
>  Common Var(flag_diagnostics_show_option) Init(1)
>  Amend appropriate diagnostic messages with the command line option that controls them
> @@ -972,9 +965,18 @@ Common Report Var(flag_expensive_optimiz
>  Perform a number of minor, expensive optimizations
>
>  fexcess-precision=
> -Common Joined RejectNegative
> +Common Joined RejectNegative Enum(excess_precision) Var(flag_excess_precision_cmdline) Init(EXCESS_PRECISION_DEFAULT)
>  -fexcess-precision=[fast|standard]     Specify handling of excess floating-point precision
>
> +Enum
> +Name(excess_precision) Type(enum excess_precision) UnknownError(unknown excess precision style %qs)
> +
> +EnumValue
> +Enum(excess_precision) String(fast) Value(EXCESS_PRECISION_FAST)
> +
> +EnumValue
> +Enum(excess_precision) String(standard) Value(EXCESS_PRECISION_STANDARD)
> +
>  ffast-math
>  Common
>
> @@ -999,9 +1001,22 @@ Common Report Var(flag_forward_propagate
>  Perform a forward propagation pass on RTL
>
>  ffp-contract=
> -Common Joined RejectNegative
> +Common Joined RejectNegative Enum(fp_contract_mode) Var(flag_fp_contract_mode) Init(FP_CONTRACT_FAST)
>  -ffp-contract=[off|on|fast] Perform floating-point expression contraction.
>
> +Enum
> +Name(fp_contract_mode) Type(enum fp_contract_mode) UnknownError(unknown floating point contraction style %qs)
> +
> +EnumValue
> +Enum(fp_contract_mode) String(off) Value(FP_CONTRACT_OFF)
> +
> +; Not implemented, fall back to conservative FP_CONTRACT_OFF.
> +EnumValue
> +Enum(fp_contract_mode) String(on) Value(FP_CONTRACT_OFF)
> +
> +EnumValue
> +Enum(fp_contract_mode) String(fast) Value(FP_CONTRACT_FAST)
> +
>  ; Nonzero means don't put addresses of constant functions in registers.
>  ; Used for compiling the Unix kernel, where strange substitutions are
>  ; done on the assembly output.
> @@ -1183,13 +1198,34 @@ Perform structure layout optimizations b
>  on profiling information.
>
>  fira-algorithm=
> -Common Joined RejectNegative
> +Common Joined RejectNegative Enum(ira_algorithm) Var(flag_ira_algorithm) Init(IRA_ALGORITHM_CB)
>  -fira-algorithm=[CB|priority] Set the used IRA algorithm
>
> +Enum
> +Name(ira_algorithm) Type(enum ira_algorithm) UnknownError(unknown IRA algorithm %qs)
> +
> +EnumValue
> +Enum(ira_algorithm) String(CB) Value(IRA_ALGORITHM_CB)
> +
> +EnumValue
> +Enum(ira_algorithm) String(priority) Value(IRA_ALGORITHM_PRIORITY)
> +
>  fira-region=
> -Common Joined RejectNegative
> +Common Joined RejectNegative Enum(ira_region) Var(flag_ira_region) Init(IRA_REGION_MIXED)
>  -fira-region=[one|all|mixed] Set regions for IRA
>
> +Enum
> +Name(ira_region) Type(enum ira_region) UnknownError(unknown IRA region %qs)
> +
> +EnumValue
> +Enum(ira_region) String(one) Value(IRA_REGION_ONE)
> +
> +EnumValue
> +Enum(ira_region) String(all) Value(IRA_REGION_ALL)
> +
> +EnumValue
> +Enum(ira_region) String(mixed) Value(IRA_REGION_MIXED)
> +
>  fira-loop-pressure
>  Common Report Var(flag_ira_loop_pressure)
>  Use IRA based register pressure calculation
> @@ -1718,9 +1754,24 @@ Common Report Var(time_report)
>  Report the time taken by each compiler pass
>
>  ftls-model=
> -Common Joined RejectNegative
> +Common Joined RejectNegative Enum(tls_model) Var(flag_tls_default) Init(TLS_MODEL_GLOBAL_DYNAMIC)
>  -ftls-model=[global-dynamic|local-dynamic|initial-exec|local-exec]     Set the default thread-local storage code generation model
>
> +Enum
> +Name(tls_model) Type(enum tls_model) UnknownError(unknown TLS model %qs)
> +
> +EnumValue
> +Enum(tls_model) String(global-dynamic) Value(TLS_MODEL_GLOBAL_DYNAMIC)
> +
> +EnumValue
> +Enum(tls_model) String(local-dynamic) Value(TLS_MODEL_LOCAL_DYNAMIC)
> +
> +EnumValue
> +Enum(tls_model) String(initial-exec) Value(TLS_MODEL_INITIAL_EXEC)
> +
> +EnumValue
> +Enum(tls_model) String(local-exec) Value(TLS_MODEL_LOCAL_EXEC)
> +
>  ftoplevel-reorder
>  Common Report Var(flag_toplevel_reorder) Init(2) Optimization
>  Reorder top level functions, variables, and asms
> @@ -1973,9 +2024,23 @@ Common Report Var(flag_verbose_asm)
>  Add extra commentary to assembler output
>
>  fvisibility=
> -Common Joined RejectNegative
> +Common Joined RejectNegative Enum(symbol_visibility) Var(default_visibility) Init(VISIBILITY_DEFAULT)
>  -fvisibility=[default|internal|hidden|protected]       Set the default symbol visibility
>
> +Enum
> +Name(symbol_visibility) Type(enum symbol_visibility) UnknownError(unrecognized visibility value %qs)
> +
> +EnumValue
> +Enum(symbol_visibility) String(default) Value(VISIBILITY_DEFAULT)
> +
> +EnumValue
> +Enum(symbol_visibility) String(internal) Value(VISIBILITY_INTERNAL)
> +
> +EnumValue
> +Enum(symbol_visibility) String(hidden) Value(VISIBILITY_HIDDEN)
> +
> +EnumValue
> +Enum(symbol_visibility) String(protected) Value(VISIBILITY_PROTECTED)
>
>  fvpt
>  Common Report Var(flag_value_profile_transformations) Optimization
> Index: gcc/opt-functions.awk
> ===================================================================
> --- gcc/opt-functions.awk       (revision 167145)
> +++ gcc/opt-functions.awk       (working copy)
> @@ -150,6 +150,10 @@ function var_type(flags)
>  {
>        if (flag_set_p("Defer", flags))
>                return "void *"
> +       else if (flag_set_p("Enum.*", flags)) {
> +               en = opt_args("Enum", flags);
> +               return enum_type[en] " "
> +       }
>        else if (!flag_set_p("Joined.*", flags) && !flag_set_p("Separate", flags))
>                return "int "
>        else if (flag_set_p("UInteger", flags))
> @@ -176,33 +180,37 @@ function var_type_struct(flags)
>  }
>
>  # Given that an option has flags FLAGS, return an initializer for the
> -# "var_cond" and "var_value" fields of its cl_options[] entry.
> +# "var_enum", "var_type" and "var_value" fields of its cl_options[] entry.
>  function var_set(flags)
>  {
>        if (flag_set_p("Defer", flags))
> -               return "CLVC_DEFER, 0"
> +               return "0, CLVC_DEFER, 0"
>        s = nth_arg(1, opt_args("Var", flags))
>        if (s != "")
> -               return "CLVC_EQUAL, " s
> +               return "0, CLVC_EQUAL, " s
>        s = opt_args("Mask", flags);
>        if (s != "") {
>                vn = var_name(flags);
>                if (vn)
> -                       return "CLVC_BIT_SET, OPTION_MASK_" s
> +                       return "0, CLVC_BIT_SET, OPTION_MASK_" s
>                else
> -                       return "CLVC_BIT_SET, MASK_" s
> +                       return "0, CLVC_BIT_SET, MASK_" s
>        }
>        s = nth_arg(0, opt_args("InverseMask", flags));
>        if (s != "") {
>                vn = var_name(flags);
>                if (vn)
> -                       return "CLVC_BIT_CLEAR, OPTION_MASK_" s
> +                       return "0, CLVC_BIT_CLEAR, OPTION_MASK_" s
>                else
> -                       return "CLVC_BIT_CLEAR, MASK_" s
> +                       return "0, CLVC_BIT_CLEAR, MASK_" s
> +       }
> +       if (flag_set_p("Enum.*", flags)) {
> +               en = opt_args("Enum", flags);
> +               return enum_index[en] ", CLVC_ENUM, 0"
>        }
>        if (var_type(flags) == "const char *")
> -               return "CLVC_STRING, 0"
> -       return "CLVC_BOOLEAN, 0"
> +               return "0, CLVC_STRING, 0"
> +       return "0, CLVC_BOOLEAN, 0"
>  }
>
>  # Given that an option called NAME has flags FLAGS, return an initializer
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
>



More information about the Gcc-patches mailing list