OSDN Git Service

2008-06-04 Xinliang David Li <davidxl@google.com>
[pf3gnuchains/gcc-fork.git] / gcc / opts.c
index 93a10d1..d86c2b3 100644 (file)
@@ -1,12 +1,13 @@
 /* Command line option handling.
-   Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    Contributed by Neil Booth.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -38,6 +38,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tm_p.h"              /* For OPTIMIZATION_OPTIONS.  */
 #include "insn-attr.h"         /* For INSN_SCHEDULING.  */
 #include "target.h"
+#include "tree-pass.h"
+#include "dbgcnt.h"
+#include "debug.h"
 
 /* Value of the -G xx switch, and whether it was passed or not.  */
 unsigned HOST_WIDE_INT g_switch_value;
@@ -55,9 +58,10 @@ bool extra_warnings;
 bool warn_larger_than;
 HOST_WIDE_INT larger_than_size;
 
-/* Nonzero means warn about constructs which might not be
-   strict-aliasing safe.  */
-int warn_strict_aliasing;
+/* True to warn about any function whose frame size is larger
+ * than N bytes. */
+bool warn_frame_larger_than;
+HOST_WIDE_INT frame_larger_than_size;
 
 /* Hack for cooperation between set_Wunused and set_Wextra.  */
 static bool maybe_warn_unused_parameter;
@@ -71,6 +75,256 @@ enum debug_info_type write_symbols = NO_DEBUG;
    the definitions of the different possible levels.  */
 enum debug_info_level debug_info_level = DINFO_LEVEL_NONE;
 
+/* A major contribution to object and executable size is debug
+   information size.  A major contribution to debug information size
+   is struct descriptions replicated in several object files. The
+   following flags attempt to reduce this information.  The basic
+   idea is to not emit struct debugging information in the current
+   compilation unit when that information will be generated by
+   another compilation unit.
+
+   Debug information for a struct defined in the current source
+   file should be generated in the object file.  Likewise the
+   debug information for a struct defined in a header should be
+   generated in the object file of the corresponding source file.
+   Both of these case are handled when the base name of the file of
+   the struct definition matches the base name of the source file
+   of the current compilation unit.  This matching emits minimal
+   struct debugging information.
+
+   The base file name matching rule above will fail to emit debug
+   information for structs defined in system headers.  So a second
+   category of files includes system headers in addition to files
+   with matching bases.
+
+   The remaining types of files are library headers and application
+   headers.  We cannot currently distinguish these two types.  */
+
+enum debug_struct_file
+{
+  DINFO_STRUCT_FILE_NONE,   /* Debug no structs. */
+  DINFO_STRUCT_FILE_BASE,   /* Debug structs defined in files with the
+                               same base name as the compilation unit. */
+  DINFO_STRUCT_FILE_SYS,    /* Also debug structs defined in system
+                               header files.  */
+  DINFO_STRUCT_FILE_ANY     /* Debug structs defined in all files. */
+};
+
+/* Generic structs (e.g. templates not explicitly specialized)
+   may not have a compilation unit associated with them, and so
+   may need to be treated differently from ordinary structs.
+
+   Structs only handled by reference (indirectly), will also usually
+   not need as much debugging information.  */
+
+static enum debug_struct_file debug_struct_ordinary[DINFO_USAGE_NUM_ENUMS]
+  = { DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY };
+static enum debug_struct_file debug_struct_generic[DINFO_USAGE_NUM_ENUMS]
+  = { DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY };
+
+/* Parse the -femit-struct-debug-detailed option value
+   and set the flag variables. */
+
+#define MATCH( prefix, string ) \
+  ((strncmp (prefix, string, sizeof prefix - 1) == 0) \
+   ? ((string += sizeof prefix - 1), 1) : 0)
+
+void
+set_struct_debug_option (const char *spec)
+{
+  /* various labels for comparison */
+  static char dfn_lbl[] = "dfn:", dir_lbl[] = "dir:", ind_lbl[] = "ind:";
+  static char ord_lbl[] = "ord:", gen_lbl[] = "gen:";
+  static char none_lbl[] = "none", any_lbl[] = "any";
+  static char base_lbl[] = "base", sys_lbl[] = "sys";
+
+  enum debug_struct_file files = DINFO_STRUCT_FILE_ANY;
+  /* Default is to apply to as much as possible. */
+  enum debug_info_usage usage = DINFO_USAGE_NUM_ENUMS;
+  int ord = 1, gen = 1;
+
+  /* What usage? */
+  if (MATCH (dfn_lbl, spec))
+    usage = DINFO_USAGE_DFN;
+  else if (MATCH (dir_lbl, spec))
+    usage = DINFO_USAGE_DIR_USE;
+  else if (MATCH (ind_lbl, spec))
+    usage = DINFO_USAGE_IND_USE;
+
+  /* Generics or not? */
+  if (MATCH (ord_lbl, spec))
+    gen = 0;
+  else if (MATCH (gen_lbl, spec))
+    ord = 0;
+
+  /* What allowable environment? */
+  if (MATCH (none_lbl, spec))
+    files = DINFO_STRUCT_FILE_NONE;
+  else if (MATCH (any_lbl, spec))
+    files = DINFO_STRUCT_FILE_ANY;
+  else if (MATCH (sys_lbl, spec))
+    files = DINFO_STRUCT_FILE_SYS;
+  else if (MATCH (base_lbl, spec))
+    files = DINFO_STRUCT_FILE_BASE;
+  else
+    error ("argument %qs to %<-femit-struct-debug-detailed%> not recognized",
+           spec);
+
+  /* Effect the specification. */
+  if (usage == DINFO_USAGE_NUM_ENUMS)
+    {
+      if (ord)
+        {
+          debug_struct_ordinary[DINFO_USAGE_DFN] = files;
+          debug_struct_ordinary[DINFO_USAGE_DIR_USE] = files;
+          debug_struct_ordinary[DINFO_USAGE_IND_USE] = files;
+        }
+      if (gen)
+        {
+          debug_struct_generic[DINFO_USAGE_DFN] = files;
+          debug_struct_generic[DINFO_USAGE_DIR_USE] = files;
+          debug_struct_generic[DINFO_USAGE_IND_USE] = files;
+        }
+    }
+  else
+    {
+      if (ord)
+        debug_struct_ordinary[usage] = files;
+      if (gen)
+        debug_struct_generic[usage] = files;
+    }
+
+  if (*spec == ',')
+    set_struct_debug_option (spec+1);
+  else
+    {
+      /* No more -femit-struct-debug-detailed specifications.
+         Do final checks. */
+      if (*spec != '\0')
+       error ("argument %qs to %<-femit-struct-debug-detailed%> unknown",
+               spec);
+      if (debug_struct_ordinary[DINFO_USAGE_DIR_USE]
+               < debug_struct_ordinary[DINFO_USAGE_IND_USE]
+         || debug_struct_generic[DINFO_USAGE_DIR_USE]
+               < debug_struct_generic[DINFO_USAGE_IND_USE])
+       error ("%<-femit-struct-debug-detailed=dir:...%> must allow at least"
+               " as much as %<-femit-struct-debug-detailed=ind:...%>");
+    }
+}
+
+/* Find the base name of a path, stripping off both directories and
+   a single final extension. */
+static int
+base_of_path (const char *path, const char **base_out)
+{
+  const char *base = path;
+  const char *dot = 0;
+  const char *p = path;
+  char c = *p;
+  while (c)
+    {
+      if (IS_DIR_SEPARATOR(c))
+        {
+          base = p + 1;
+          dot = 0;
+        }
+      else if (c == '.')
+        dot = p;
+      c = *++p;
+    }
+  if (!dot)
+    dot = p;
+  *base_out = base;
+  return dot - base;
+}
+
+/* Match the base name of a file to the base name of a compilation unit. */
+
+static const char *main_input_basename;
+static int main_input_baselength;
+
+static int
+matches_main_base (const char *path)
+{
+  /* Cache the last query. */
+  static const char *last_path = NULL;
+  static int last_match = 0;
+  if (path != last_path)
+    {
+      const char *base;
+      int length = base_of_path (path, &base);
+      last_path = path;
+      last_match = (length == main_input_baselength
+                    && memcmp (base, main_input_basename, length) == 0);
+    }
+  return last_match;
+}
+
+#ifdef DEBUG_DEBUG_STRUCT
+
+static int
+dump_struct_debug (tree type, enum debug_info_usage usage,
+                  enum debug_struct_file criterion, int generic,
+                  int matches, int result)
+{
+  /* Find the type name. */
+  tree type_decl = TYPE_STUB_DECL (type);
+  tree t = type_decl;
+  const char *name = 0;
+  if (TREE_CODE (t) == TYPE_DECL)
+    t = DECL_NAME (t);
+  if (t)
+    name = IDENTIFIER_POINTER (t);
+
+  fprintf (stderr, "   struct %d %s %s %s %s %d %p %s\n",
+          criterion,
+           DECL_IN_SYSTEM_HEADER (type_decl) ? "sys" : "usr",
+           matches ? "bas" : "hdr",
+           generic ? "gen" : "ord",
+           usage == DINFO_USAGE_DFN ? ";" :
+             usage == DINFO_USAGE_DIR_USE ? "." : "*",
+           result,
+           (void*) type_decl, name);
+  return result;
+}
+#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \
+  dump_struct_debug (type, usage, criterion, generic, matches, result)
+
+#else
+
+#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \
+  (result)
+
+#endif
+
+
+bool
+should_emit_struct_debug (tree type, enum debug_info_usage usage)
+{
+  enum debug_struct_file criterion;
+  tree type_decl;
+  bool generic = lang_hooks.types.generic_p (type);
+
+  if (generic)
+    criterion = debug_struct_generic[usage];
+  else
+    criterion = debug_struct_ordinary[usage];
+
+  if (criterion == DINFO_STRUCT_FILE_NONE)
+    return DUMP_GSTRUCT (type, usage, criterion, generic, false, false);
+  if (criterion == DINFO_STRUCT_FILE_ANY)
+    return DUMP_GSTRUCT (type, usage, criterion, generic, false, true);
+
+  type_decl = TYPE_STUB_DECL (type);
+
+  if (criterion == DINFO_STRUCT_FILE_SYS && DECL_IN_SYSTEM_HEADER (type_decl))
+    return DUMP_GSTRUCT (type, usage, criterion, generic, false, true);
+
+  if (matches_main_base (DECL_SOURCE_FILE (type_decl)))
+    return DUMP_GSTRUCT (type, usage, criterion, generic, true, true);
+  return DUMP_GSTRUCT (type, usage, criterion, generic, false, false);
+}
+
 /* Nonzero means use GNU-only extensions in the generated symbolic
    debugging information.  Currently, this only has an effect when
    write_symbols is set to DBX_DEBUG, XCOFF_DEBUG, or DWARF_DEBUG.  */
@@ -79,29 +333,50 @@ bool use_gnu_debug_info_extensions;
 /* The default visibility for all symbols (unless overridden) */
 enum symbol_visibility default_visibility = VISIBILITY_DEFAULT;
 
+/* Disable unit-at-a-time for frontends that might be still broken in this
+   respect.  */
+
+bool no_unit_at_a_time_default;
+
 /* Global visibility options.  */
 struct visibility_flags visibility_options;
 
-/* Columns of --help display.  */
-static unsigned int columns = 80;
-
 /* What to print when a switch has no documentation.  */
+#ifdef ENABLE_CHECKING
 static const char undocumented_msg[] = N_("This switch lacks documentation");
+#else
+static const char undocumented_msg[] = "";
+#endif
 
 /* Used for bookkeeping on whether user set these flags so
    -fprofile-use/-fprofile-generate does not use them.  */
 static bool profile_arc_flag_set, flag_profile_values_set;
 static bool flag_unroll_loops_set, flag_tracer_set;
 static bool flag_value_profile_transformations_set;
-bool flag_speculative_prefetching_set;
 static bool flag_peel_loops_set, flag_branch_probabilities_set;
+static bool flag_inline_functions_set;
+
+/* Functions excluded from profiling.  */
+
+typedef char *char_p; /* For DEF_VEC_P.  */
+DEF_VEC_P(char_p);
+DEF_VEC_ALLOC_P(char_p,heap);
+
+static VEC(char_p,heap) *flag_instrument_functions_exclude_functions;
+static VEC(char_p,heap) *flag_instrument_functions_exclude_files;
+
+typedef const char *const_char_p; /* For DEF_VEC_P.  */
+DEF_VEC_P(const_char_p);
+DEF_VEC_ALLOC_P(const_char_p,heap);
+
+static VEC(const_char_p,heap) *ignored_options;
 
 /* Input file names.  */
 const char **in_fnames;
 unsigned num_in_fnames;
 
-static size_t find_opt (const char *, int);
-static int common_handle_option (size_t scode, const char *arg, int value);
+static int common_handle_option (size_t scode, const char *arg, int value,
+                                unsigned int lang_mask);
 static void handle_param (const char *);
 static void set_Wextra (int);
 static unsigned int handle_option (const char **argv, unsigned int lang_mask);
@@ -109,98 +384,9 @@ static char *write_langs (unsigned int lang_mask);
 static void complain_wrong_lang (const char *, const struct cl_option *,
                                 unsigned int lang_mask);
 static void handle_options (unsigned int, const char **, unsigned int);
-static void wrap_help (const char *help, const char *item, unsigned int);
-static void print_help (void);
-static void print_param_help (void);
-static void print_filtered_help (unsigned int flag);
-static unsigned int print_switch (const char *text, unsigned int indent);
 static void set_debug_level (enum debug_info_type type, int extended,
                             const char *arg);
 
-/* Perform a binary search to find which option the command-line INPUT
-   matches.  Returns its index in the option array, and N_OPTS
-   (cl_options_count) on failure.
-
-   This routine is quite subtle.  A normal binary search is not good
-   enough because some options can be suffixed with an argument, and
-   multiple sub-matches can occur, e.g. input of "-pedantic" matching
-   the initial substring of "-pedantic-errors".
-
-   A more complicated example is -gstabs.  It should match "-g" with
-   an argument of "stabs".  Suppose, however, that the number and list
-   of switches are such that the binary search tests "-gen-decls"
-   before having tested "-g".  This doesn't match, and as "-gen-decls"
-   is less than "-gstabs", it will become the lower bound of the
-   binary search range, and "-g" will never be seen.  To resolve this
-   issue, opts.sh makes "-gen-decls" point, via the back_chain member,
-   to "-g" so that failed searches that end between "-gen-decls" and
-   the lexicographically subsequent switch know to go back and see if
-   "-g" causes a match (which it does in this example).
-
-   This search is done in such a way that the longest match for the
-   front end in question wins.  If there is no match for the current
-   front end, the longest match for a different front end is returned
-   (or N_OPTS if none) and the caller emits an error message.  */
-static size_t
-find_opt (const char *input, int lang_mask)
-{
-  size_t mn, mx, md, opt_len;
-  size_t match_wrong_lang;
-  int comp;
-
-  mn = 0;
-  mx = cl_options_count;
-
-  /* Find mn such this lexicographical inequality holds:
-     cl_options[mn] <= input < cl_options[mn + 1].  */
-  while (mx - mn > 1)
-    {
-      md = (mn + mx) / 2;
-      opt_len = cl_options[md].opt_len;
-      comp = strncmp (input, cl_options[md].opt_text + 1, opt_len);
-
-      if (comp < 0)
-       mx = md;
-      else
-       mn = md;
-    }
-
-  /* This is the switch that is the best match but for a different
-     front end, or cl_options_count if there is no match at all.  */
-  match_wrong_lang = cl_options_count;
-
-  /* Backtrace the chain of possible matches, returning the longest
-     one, if any, that fits best.  With current GCC switches, this
-     loop executes at most twice.  */
-  do
-    {
-      const struct cl_option *opt = &cl_options[mn];
-
-      /* Is this switch a prefix of the input?  */
-      if (!strncmp (input, opt->opt_text + 1, opt->opt_len))
-       {
-         /* If language is OK, and the match is exact or the switch
-            takes a joined argument, return it.  */
-         if ((opt->flags & lang_mask)
-             && (input[opt->opt_len] == '\0' || (opt->flags & CL_JOINED)))
-           return mn;
-
-         /* If we haven't remembered a prior match, remember this
-            one.  Any prior match is necessarily better.  */
-         if (match_wrong_lang == cl_options_count)
-           match_wrong_lang = mn;
-       }
-
-      /* Try the next possibility.  This is cl_options_count if there
-        are no more.  */
-      mn = opt->back_chain;
-    }
-  while (mn != cl_options_count);
-
-  /* Return the best wrong match, or cl_options_count if none.  */
-  return match_wrong_lang;
-}
-
 /* If ARG is a non-negative integer made up solely of digits, return its
    value, otherwise return -1.  */
 static int
@@ -229,7 +415,7 @@ write_langs (unsigned int mask)
     if (mask & (1U << n))
       len += strlen (lang_name) + 1;
 
-  result = xmalloc (len);
+  result = XNEWVEC (char, len);
   len = 0;
   for (n = 0; (lang_name = lang_names[n]) != 0; n++)
     if (mask & (1U << n))
@@ -256,13 +442,40 @@ complain_wrong_lang (const char *text, const struct cl_option *option,
   bad_lang = write_langs (lang_mask);
 
   /* Eventually this should become a hard error IMO.  */
-  warning ("command line option \"%s\" is valid for %s but not for %s",
+  warning (0, "command line option \"%s\" is valid for %s but not for %s",
           text, ok_langs, bad_lang);
 
   free (ok_langs);
   free (bad_lang);
 }
 
+/* Buffer the unknown option described by the string OPT.  Currently,
+   we only complain about unknown -Wno-* options if they may have
+   prevented a diagnostic. Otherwise, we just ignore them.  */
+
+static void postpone_unknown_option_error(const char *opt)
+{
+  VEC_safe_push (const_char_p, heap, ignored_options, opt);
+}
+
+/* Produce an error for each option previously buffered.  */
+
+void print_ignored_options (void)
+{
+  location_t saved_loc = input_location;
+
+  input_location = 0;
+
+  while (!VEC_empty (const_char_p, ignored_options))
+    {
+      const char *opt;
+      opt = VEC_pop (const_char_p, ignored_options);
+      error ("unrecognized command line option \"%s\"", opt);
+    }
+
+  input_location = saved_loc;
+}
+
 /* Handle the switch beginning at ARGV for the language indicated by
    LANG_MASK.  Returns the number of switches consumed.  */
 static unsigned int
@@ -277,21 +490,31 @@ handle_option (const char **argv, unsigned int lang_mask)
 
   opt = argv[0];
 
-  /* Drop the "no-" from negative switches.  */
-  if ((opt[1] == 'W' || opt[1] == 'f')
+  opt_index = find_opt (opt + 1, lang_mask | CL_COMMON | CL_TARGET);
+  if (opt_index == cl_options_count
+      && (opt[1] == 'W' || opt[1] == 'f' || opt[1] == 'm')
       && opt[2] == 'n' && opt[3] == 'o' && opt[4] == '-')
     {
+      /* Drop the "no-" from negative switches.  */
       size_t len = strlen (opt) - 3;
 
-      dup = xmalloc (len + 1);
+      dup = XNEWVEC (char, len + 1);
       dup[0] = '-';
       dup[1] = opt[1];
       memcpy (dup + 2, opt + 5, len - 2 + 1);
       opt = dup;
       value = 0;
+      opt_index = find_opt (opt + 1, lang_mask | CL_COMMON | CL_TARGET);
+      if (opt_index == cl_options_count && opt[1] == 'W')
+       {
+         /* We don't generate errors for unknown -Wno-* options
+             unless we issue diagnostics.  */
+         postpone_unknown_option_error (argv[0]);
+         result = 1;
+         goto done;
+       }
     }
 
-  opt_index = find_opt (opt + 1, lang_mask | CL_COMMON);
   if (opt_index == cl_options_count)
     goto done;
 
@@ -305,6 +528,14 @@ handle_option (const char **argv, unsigned int lang_mask)
   /* We've recognized this switch.  */
   result = 1;
 
+  /* Check to see if the option is disabled for this configuration.  */
+  if (option->flags & CL_DISABLED)
+    {
+      error ("command line option %qs"
+            " is not supported by this configuration", opt);
+      goto done;
+    }
+
   /* Sort out any argument the switch takes.  */
   if (option->flags & CL_JOINED)
     {
@@ -335,11 +566,20 @@ handle_option (const char **argv, unsigned int lang_mask)
 
   /* Now we've swallowed any potential argument, complain if this
      is a switch for a different front end.  */
-  if (!(option->flags & (lang_mask | CL_COMMON)))
+  if (!(option->flags & (lang_mask | CL_COMMON | CL_TARGET)))
     {
       complain_wrong_lang (argv[0], option, lang_mask);
       goto done;
     }
+  else if ((option->flags & CL_TARGET)
+          && (option->flags & CL_LANG_ALL)
+          && !(option->flags & lang_mask))
+    {
+      /* Complain for target flag language mismatches if any languages
+        are specified.  */
+      complain_wrong_lang (argv[0], option, lang_mask);
+      goto done;
+    }
 
   if (arg == NULL && (option->flags & (CL_JOINED | CL_SEPARATE)))
     {
@@ -361,24 +601,43 @@ handle_option (const char **argv, unsigned int lang_mask)
     }
 
   if (option->flag_var)
-    {
-      if (option->has_set_value)
-       {
-         if (value)
-           *option->flag_var = option->set_value;
-         else
-           *option->flag_var = !option->set_value;
-       }
-      else
-       *option->flag_var = value;
-    }
-  
+    switch (option->var_type)
+      {
+      case CLVC_BOOLEAN:
+       *(int *) option->flag_var = value;
+       break;
+
+      case CLVC_EQUAL:
+       *(int *) option->flag_var = (value
+                                    ? option->var_value
+                                    : !option->var_value);
+       break;
+
+      case CLVC_BIT_CLEAR:
+      case CLVC_BIT_SET:
+       if ((value != 0) == (option->var_type == CLVC_BIT_SET))
+         *(int *) option->flag_var |= option->var_value;
+       else
+         *(int *) option->flag_var &= ~option->var_value;
+       if (option->flag_var == &target_flags)
+         target_flags_explicit |= option->var_value;
+       break;
+
+      case CLVC_STRING:
+       *(const char **) option->flag_var = arg;
+       break;
+      }
+
   if (option->flags & lang_mask)
     if (lang_hooks.handle_option (opt_index, arg, value) == 0)
       result = 0;
 
   if (result && (option->flags & CL_COMMON))
-    if (common_handle_option (opt_index, arg, value) == 0)
+    if (common_handle_option (opt_index, arg, value, lang_mask) == 0)
+      result = 0;
+
+  if (result && (option->flags & CL_TARGET))
+    if (!targetm.handle_option (opt_index, arg, value))
       result = 0;
 
  done:
@@ -387,6 +646,96 @@ handle_option (const char **argv, unsigned int lang_mask)
   return result;
 }
 
+/* Handle FILENAME from the command line.  */
+static void
+add_input_filename (const char *filename)
+{
+  num_in_fnames++;
+  in_fnames = xrealloc (in_fnames, num_in_fnames * sizeof (in_fnames[0]));
+  in_fnames[num_in_fnames - 1] = filename;
+}
+
+/* Add functions or file names to a vector of names to exclude from
+   instrumentation.  */
+
+static void
+add_instrument_functions_exclude_list (VEC(char_p,heap) **pvec,
+                                      const char* arg)
+{
+  char *tmp;
+  char *r;
+  char *w;
+  char *token_start;
+
+  /* We never free this string.  */
+  tmp = xstrdup (arg);
+
+  r = tmp;
+  w = tmp;
+  token_start = tmp;
+
+  while (*r != '\0')
+    {
+      if (*r == ',')
+       {
+         *w++ = '\0';
+         ++r;
+         VEC_safe_push (char_p, heap, *pvec, token_start);
+         token_start = w;
+       }
+      if (*r == '\\' && r[1] == ',')
+       {
+         *w++ = ',';
+         r += 2;
+       }
+      else
+       *w++ = *r++;
+    }
+  if (*token_start != '\0')
+    VEC_safe_push (char_p, heap, *pvec, token_start);
+}
+
+/* Return whether we should exclude FNDECL from instrumentation.  */
+
+bool
+flag_instrument_functions_exclude_p (tree fndecl)
+{
+  if (VEC_length (char_p, flag_instrument_functions_exclude_functions) > 0)
+    {
+      const char *name;
+      int i;
+      char *s;
+
+      name = lang_hooks.decl_printable_name (fndecl, 0);
+      for (i = 0;
+          VEC_iterate (char_p, flag_instrument_functions_exclude_functions,
+                       i, s);
+          ++i)
+       {
+         if (strstr (name, s) != NULL)
+           return true;
+       }
+    }
+
+  if (VEC_length (char_p, flag_instrument_functions_exclude_files) > 0)
+    {
+      const char *name;
+      int i;
+      char *s;
+
+      name = DECL_SOURCE_FILE (fndecl);
+      for (i = 0;
+          VEC_iterate (char_p, flag_instrument_functions_exclude_files, i, s);
+          ++i)
+       {
+         if (strstr (name, s) != NULL)
+           return true;
+       }
+    }
+
+  return false;
+}
+
 /* Decode and handle the vector of command line options.  LANG_MASK
    contains has a single bit set representing the current
    language.  */
@@ -403,7 +752,11 @@ handle_options (unsigned int argc, const char **argv, unsigned int lang_mask)
       if (opt[0] != '-' || opt[1] == '\0')
        {
          if (main_input_filename == NULL)
-           main_input_filename = opt;
+           {
+             main_input_filename = opt;
+             main_input_baselength
+               = base_of_path (main_input_filename, &main_input_basename);
+           }
          add_input_filename (opt);
          n = 1;
          continue;
@@ -419,15 +772,6 @@ handle_options (unsigned int argc, const char **argv, unsigned int lang_mask)
     }
 }
 
-/* Handle FILENAME from the command line.  */
-void
-add_input_filename (const char *filename)
-{
-  num_in_fnames++;
-  in_fnames = xrealloc (in_fnames, num_in_fnames * sizeof (in_fnames[0]));
-  in_fnames[num_in_fnames - 1] = filename;
-}
-
 /* Parse command line options and set default flag values.  Do minimal
    options processing.  */
 void
@@ -481,7 +825,6 @@ decode_options (unsigned int argc, const char **argv)
   if (optimize >= 1)
     {
       flag_defer_pop = 1;
-      flag_thread_jumps = 1;
 #ifdef DELAY_SLOTS
       flag_delayed_branch = 1;
 #endif
@@ -490,18 +833,23 @@ decode_options (unsigned int argc, const char **argv)
 #endif
       flag_guess_branch_prob = 1;
       flag_cprop_registers = 1;
-      flag_loop_optimize = 1;
       flag_if_conversion = 1;
       flag_if_conversion2 = 1;
+      flag_ipa_pure_const = 1;
+      flag_ipa_reference = 1;
+      flag_split_wide_types = 1;
       flag_tree_ccp = 1;
       flag_tree_dce = 1;
       flag_tree_dom = 1;
       flag_tree_dse = 1;
       flag_tree_ter = 1;
-      flag_tree_live_range_split = 1;
       flag_tree_sra = 1;
       flag_tree_copyrename = 1;
       flag_tree_fre = 1;
+      flag_tree_copy_prop = 1;
+      flag_tree_sink = 1;
+      if (!no_unit_at_a_time_default)
+        flag_unit_at_a_time = 1;
 
       if (!optimize_size)
        {
@@ -510,25 +858,21 @@ decode_options (unsigned int argc, const char **argv)
             the condition is satisfied in the first iteration and therefore
             to eliminate it.  Jump threading handles these cases now.  */
          flag_tree_ch = 1;
-          /* PRE tends to generate bigger code.  */
-          flag_tree_pre = 1;
        }
     }
 
   if (optimize >= 2)
     {
+      flag_inline_small_functions = 1;
+      flag_thread_jumps = 1;
       flag_crossjumping = 1;
       flag_optimize_sibling_calls = 1;
+      flag_forward_propagate = 1;
       flag_cse_follow_jumps = 1;
-      flag_cse_skip_blocks = 1;
       flag_gcse = 1;
       flag_expensive_optimizations = 1;
-      flag_strength_reduce = 1;
       flag_rerun_cse_after_loop = 1;
-      flag_rerun_loop_opt = 1;
       flag_caller_saves = 1;
-      flag_force_mem = 1;
       flag_peephole2 = 1;
 #ifdef INSN_SCHEDULING
       flag_schedule_insns = 1;
@@ -536,17 +880,36 @@ decode_options (unsigned int argc, const char **argv)
 #endif
       flag_regmove = 1;
       flag_strict_aliasing = 1;
+      flag_strict_overflow = 1;
       flag_delete_null_pointer_checks = 1;
       flag_reorder_blocks = 1;
       flag_reorder_functions = 1;
-      flag_unit_at_a_time = 1;
+      flag_tree_store_ccp = 1;
+      flag_tree_vrp = 1;
+
+      if (!optimize_size)
+       {
+          /* Conditional DCE generates bigger code.  */
+          flag_tree_builtin_call_dce = 1;
+          /* PRE tends to generate bigger code.  */
+          flag_tree_pre = 1;
+       }
+
+      /* Allow more virtual operators to increase alias precision.  */
+      set_param_value ("max-aliased-vops", 500);
     }
 
   if (optimize >= 3)
     {
+      flag_predictive_commoning = 1;
       flag_inline_functions = 1;
       flag_unswitch_loops = 1;
       flag_gcse_after_reload = 1;
+      flag_tree_vectorize = 1;
+
+      /* Allow even more virtual operators.  */
+      set_param_value ("max-aliased-vops", 1000);
+      set_param_value ("avg-aliased-vops", 3);
     }
 
   if (optimize < 2 || optimize_size)
@@ -569,10 +932,8 @@ decode_options (unsigned int argc, const char **argv)
 
   if (optimize_size)
     {
-      /* Inlining of very small functions usually reduces total size.  */
-      set_param_value ("max-inline-insns-single", 5);
-      set_param_value ("max-inline-insns-auto", 5);
-      set_param_value ("max-inline-insns-rtl", 10);
+      /* Inlining of functions reducing size is a good idea regardless
+        of them being declared inline.  */
       flag_inline_functions = 1;
 
       /* We want to crossjump as much as possible.  */
@@ -587,14 +948,10 @@ decode_options (unsigned int argc, const char **argv)
 
   /* Initialize target_flags before OPTIMIZATION_OPTIONS so the latter can
      modify it.  */
-  target_flags = 0;
-  set_target_switch ("");
+  target_flags = targetm.default_target_flags;
 
-  /* Unwind tables are always present when a target has ABI-specified unwind
-     tables, so the default should be ON.  */
-#ifdef TARGET_UNWIND_INFO
-  flag_unwind_tables = TARGET_UNWIND_INFO;
-#endif
+  /* Some tagets have ABI-specified unwind tables.  */
+  flag_unwind_tables = targetm.unwind_tables_default;
 
 #ifdef OPTIMIZATION_OPTIONS
   /* Allow default optimizations to be specified on a per-machine basis.  */
@@ -603,63 +960,389 @@ decode_options (unsigned int argc, const char **argv)
 
   handle_options (argc, argv, lang_mask);
 
-  if (flag_pie)
-    flag_pic = flag_pie;
-  if (flag_pic && !flag_pie)
-    flag_shlib = 1;
+  if (flag_pie)
+    flag_pic = flag_pie;
+  if (flag_pic && !flag_pie)
+    flag_shlib = 1;
+
+  if (flag_no_inline == 2)
+    flag_no_inline = 0;
+  else
+    flag_really_no_inline = flag_no_inline;
+
+  /* Set flag_no_inline before the post_options () hook.  The C front
+     ends use it to determine tree inlining defaults.  FIXME: such
+     code should be lang-independent when all front ends use tree
+     inlining, in which case it, and this condition, should be moved
+     to the top of process_options() instead.  */
+  if (optimize == 0)
+    {
+      /* Inlining does not work if not optimizing,
+        so force it not to be done.  */
+      flag_no_inline = 1;
+      warn_inline = 0;
+
+      /* The c_decode_option function and decode_option hook set
+        this to `2' if -Wall is used, so we can avoid giving out
+        lots of errors for people who don't realize what -Wall does.  */
+      if (warn_uninitialized == 1)
+       warning (OPT_Wuninitialized,
+                "-Wuninitialized is not supported without -O");
+    }
+
+  if (flag_really_no_inline == 2)
+    flag_really_no_inline = flag_no_inline;
+
+  /* Inlining of functions called just once will only work if we can look
+     at the complete translation unit.  */
+  if (flag_inline_functions_called_once && !flag_unit_at_a_time)
+    {
+      flag_inline_functions_called_once = 0;
+      warning (OPT_Wdisabled_optimization,
+              "-funit-at-a-time is required for inlining of functions "
+              "that are only called once");
+    }
+
+  /* The optimization to partition hot and cold basic blocks into separate
+     sections of the .o and executable files does not work (currently)
+     with exception handling.  This is because there is no support for
+     generating unwind info.  If flag_exceptions is turned on we need to
+     turn off the partitioning optimization.  */
+
+  if (flag_exceptions && flag_reorder_blocks_and_partition)
+    {
+      inform
+           ("-freorder-blocks-and-partition does not work with exceptions");
+      flag_reorder_blocks_and_partition = 0;
+      flag_reorder_blocks = 1;
+    }
+
+  /* If user requested unwind info, then turn off the partitioning
+     optimization.  */
+
+  if (flag_unwind_tables && ! targetm.unwind_tables_default
+      && flag_reorder_blocks_and_partition)
+    {
+      inform ("-freorder-blocks-and-partition does not support unwind info");
+      flag_reorder_blocks_and_partition = 0;
+      flag_reorder_blocks = 1;
+    }
+
+  /* If the target requested unwind info, then turn off the partitioning
+     optimization with a different message.  Likewise, if the target does not
+     support named sections.  */
+
+  if (flag_reorder_blocks_and_partition
+      && (!targetm.have_named_sections
+         || (flag_unwind_tables && targetm.unwind_tables_default)))
+    {
+      inform
+       ("-freorder-blocks-and-partition does not work on this architecture");
+      flag_reorder_blocks_and_partition = 0;
+      flag_reorder_blocks = 1;
+    }
+}
+
+#define LEFT_COLUMN    27
+
+/* Output ITEM, of length ITEM_WIDTH, in the left column,
+   followed by word-wrapped HELP in a second column.  */
+static void
+wrap_help (const char *help,
+          const char *item,
+          unsigned int item_width,
+          unsigned int columns)
+{
+  unsigned int col_width = LEFT_COLUMN;
+  unsigned int remaining, room, len;
+
+  remaining = strlen (help);
+
+  do
+    {
+      room = columns - 3 - MAX (col_width, item_width);
+      if (room > columns)
+       room = 0;
+      len = remaining;
+
+      if (room < len)
+       {
+         unsigned int i;
+
+         for (i = 0; help[i]; i++)
+           {
+             if (i >= room && len != remaining)
+               break;
+             if (help[i] == ' ')
+               len = i;
+             else if ((help[i] == '-' || help[i] == '/')
+                      && help[i + 1] != ' '
+                      && i > 0 && ISALPHA (help[i - 1]))
+               len = i + 1;
+           }
+       }
+
+      printf( "  %-*.*s %.*s\n", col_width, item_width, item, len, help);
+      item_width = 0;
+      while (help[len] == ' ')
+       len++;
+      help += len;
+      remaining -= len;
+    }
+  while (remaining);
+}
+
+/* Print help for a specific front-end, etc.  */
+static void
+print_filtered_help (unsigned int include_flags,
+                    unsigned int exclude_flags,
+                    unsigned int any_flags,
+                    unsigned int columns)
+{
+  unsigned int i;
+  const char *help;
+  static char *printed = NULL;
+  bool found = false;
+  bool displayed = false;
+
+  if (include_flags == CL_PARAMS)
+    {
+      for (i = 0; i < LAST_PARAM; i++)
+       {
+         const char *param = compiler_params[i].option;
+
+         help = compiler_params[i].help;
+         if (help == NULL || *help == '\0')
+           {
+             if (exclude_flags & CL_UNDOCUMENTED)
+               continue;
+             help = undocumented_msg;
+           }
+
+         /* Get the translation.  */
+         help = _(help);
+
+         wrap_help (help, param, strlen (param), columns);
+       }
+      putchar ('\n');
+      return;
+    }
+
+  if (!printed)
+    printed = xcalloc (1, cl_options_count);
+
+  for (i = 0; i < cl_options_count; i++)
+    {
+      static char new_help[128];
+      const struct cl_option *option = cl_options + i;
+      unsigned int len;
+      const char *opt;
+      const char *tab;
+
+      if (include_flags == 0
+         || ((option->flags & include_flags) != include_flags))
+       {
+         if ((option->flags & any_flags) == 0)
+           continue;
+       }
+
+      /* Skip unwanted switches.  */
+      if ((option->flags & exclude_flags) != 0)
+       continue;
+
+      found = true;
+      /* Skip switches that have already been printed.  */
+      if (printed[i])
+       continue;
+
+      printed[i] = true;
+
+      help = option->help;
+      if (help == NULL)
+       {
+         if (exclude_flags & CL_UNDOCUMENTED)
+           continue;
+         help = undocumented_msg;
+       }
+
+      /* Get the translation.  */
+      help = _(help);
+
+      /* Find the gap between the name of the
+        option and its descriptive text.  */
+      tab = strchr (help, '\t');
+      if (tab)
+       {
+         len = tab - help;
+         opt = help;
+         help = tab + 1;
+       }
+      else
+       {
+         opt = option->opt_text;
+         len = strlen (opt);
+       }
+
+      /* With the -Q option enabled we change the descriptive text associated
+        with an option to be an indication of its current setting.  */
+      if (!quiet_flag)
+       {
+         if (len < (LEFT_COLUMN + 2))
+           strcpy (new_help, "\t\t");
+         else
+           strcpy (new_help, "\t");
+
+         if (option->flag_var != NULL)
+           {
+             if (option->flags & CL_JOINED)
+               {
+                 if (option->var_type == CLVC_STRING)
+                   {
+                     if (* (const char **) option->flag_var != NULL)
+                       snprintf (new_help + strlen (new_help),
+                                 sizeof (new_help) - strlen (new_help),
+                                 * (const char **) option->flag_var);
+                   }
+                 else
+                   sprintf (new_help + strlen (new_help),
+                            "%#x", * (int *) option->flag_var);
+               }
+             else
+               strcat (new_help, option_enabled (i)
+                       ? _("[enabled]") : _("[disabled]"));
+           }
+
+         help = new_help;
+       }
+
+      wrap_help (help, opt, len, columns);
+      displayed = true;
+    }
+
+  if (! found)
+    {
+      unsigned int langs = include_flags & CL_LANG_ALL;
+
+      if (langs == 0)
+       printf (_(" No options with the desired characteristics were found\n"));
+      else
+       {
+         unsigned int i;
+
+         /* PR 31349: Tell the user how to see all of the
+            options supported by a specific front end.  */
+         for (i = 0; (1U << i) < CL_LANG_ALL; i ++)
+           if ((1U << i) & langs)
+             printf (_(" None found.  Use --help=%s to show *all* the options supported by the %s front-end\n"),
+                     lang_names[i], lang_names[i]);
+       }
+       
+    }
+  else if (! displayed)
+    printf (_(" All options with the desired characteristics have already been displayed\n"));
+
+  putchar ('\n');
+}
+
+/* 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.  */
+static void
+print_specific_help (unsigned int include_flags,
+                    unsigned int exclude_flags,
+                    unsigned int any_flags)
+{
+  unsigned int all_langs_mask = (1U << cl_lang_count) - 1;
+  const char * description = NULL;
+  const char * descrip_extra = "";
+  size_t i;
+  unsigned int flag;
+  static unsigned int columns = 0;
 
-  if (flag_no_inline == 2)
-    flag_no_inline = 0;
-  else
-    flag_really_no_inline = flag_no_inline;
+  /* Sanity check: Make sure that we do not have more
+     languages than we have bits available to enumerate them.  */
+  gcc_assert ((1U << cl_lang_count) < CL_MIN_OPTION_CLASS);
 
-  /* Set flag_no_inline before the post_options () hook.  The C front
-     ends use it to determine tree inlining defaults.  FIXME: such
-     code should be lang-independent when all front ends use tree
-     inlining, in which case it, and this condition, should be moved
-     to the top of process_options() instead.  */
-  if (optimize == 0)
+  /* If we have not done so already, obtain
+     the desired maximum width of the output.  */
+  if (columns == 0)
     {
-      /* Inlining does not work if not optimizing,
-        so force it not to be done.  */
-      flag_no_inline = 1;
-      warn_inline = 0;
+      const char *p;
 
-      /* The c_decode_option function and decode_option hook set
-        this to `2' if -Wall is used, so we can avoid giving out
-        lots of errors for people who don't realize what -Wall does.  */
-      if (warn_uninitialized == 1)
-       warning ("-Wuninitialized is not supported without -O");
-    }
+      GET_ENVIRONMENT (p, "COLUMNS");
+      if (p != NULL)
+       {
+         int value = atoi (p);
 
-  if (flag_really_no_inline == 2)
-    flag_really_no_inline = flag_no_inline;
+         if (value > 0)
+           columns = value;
+       }
 
-  /* The optimization to partition hot and cold basic blocks into separate
-     sections of the .o and executable files does not work (currently)
-     with exception handling.  If flag_exceptions is turned on we need to
-     turn off the partitioning optimization.  */
+      if (columns == 0)
+       /* Use a reasonable default.  */
+       columns = 80;
+    }
 
-  if (flag_exceptions && flag_reorder_blocks_and_partition)
+  /* Decide upon the title for the options that we are going to display.  */
+  for (i = 0, flag = 1; flag <= CL_MAX_OPTION_CLASS; flag <<= 1, i ++)
     {
-      warning 
-           ("-freorder-blocks-and-partition does not work with exceptions");
-      flag_reorder_blocks_and_partition = 0;
-      flag_reorder_blocks = 1;
+      switch (flag & include_flags)
+       {
+       case 0:
+         break;
+
+       case CL_TARGET:
+         description = _("The following options are target specific");
+         break;
+       case CL_WARNING:
+         description = _("The following options control compiler warning messages");
+         break;
+       case CL_OPTIMIZATION:
+         description = _("The following options control optimizations");
+         break;
+       case CL_COMMON:
+         description = _("The following options are language-independent");
+         break;
+       case CL_PARAMS:
+         description = _("The --param option recognizes the following as parameters");
+         break;
+       default:
+         if (i >= cl_lang_count)
+           break;
+         if ((exclude_flags & ((1U << cl_lang_count) - 1)) != 0)
+           description = _("The following options are specific to just the language ");
+         else
+           description = _("The following options are supported by the language ");
+         descrip_extra = lang_names [i];
+         break;
+       }
     }
 
-  /* The optimization to partition hot and cold basic blocks into
-     separate sections of the .o and executable files does not currently
-     work correctly with DWARF debugging turned on.  Until this is fixed
-     we will disable the optimization when DWARF debugging is set.  */
-  
-  if (flag_reorder_blocks_and_partition && write_symbols == DWARF2_DEBUG)
+  if (description == NULL)
     {
-      warning
-       ("-freorder-blocks-and-partition does not work with -g (currently)");
-      flag_reorder_blocks_and_partition = 0;
-      flag_reorder_blocks = 1;
+      if (any_flags == 0)
+       {
+         if (include_flags == CL_UNDOCUMENTED)
+           description = _("The following options are not documented");
+         else
+           {
+             internal_error ("unrecognized include_flags 0x%x passed to print_specific_help",
+                             include_flags);
+             return;
+           }
+       }
+      else
+       {
+         if (any_flags & all_langs_mask)
+           description = _("The following options are language-related");
+         else
+           description = _("The following options are language-independent");
+       }
     }
+
+  printf ("%s%s:\n", description, descrip_extra);
+  print_filtered_help (include_flags, exclude_flags, any_flags, columns);
 }
 
 /* Handle target- and language-independent options.  Return zero to
@@ -668,26 +1351,167 @@ decode_options (unsigned int argc, const char **argv)
    VALUE assigned to a variable, it happens automatically.  */
 
 static int
-common_handle_option (size_t scode, const char *arg, int value)
+common_handle_option (size_t scode, const char *arg, int value,
+                     unsigned int lang_mask)
 {
+  static bool verbose = false;
   enum opt_code code = (enum opt_code) scode;
 
   switch (code)
     {
-    case OPT__help:
-      print_help ();
-      exit_after_options = true;
-      break;
-
     case OPT__param:
       handle_param (arg);
       break;
 
+    case OPT_v:
+      verbose = true;
+      break;
+
+    case OPT_fhelp:
+    case OPT__help:
+      {
+       unsigned int all_langs_mask = (1U << cl_lang_count) - 1;
+       unsigned int undoc_mask;
+       unsigned int i;
+
+       undoc_mask = (verbose | extra_warnings) ? 0 : CL_UNDOCUMENTED;
+       /* 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);
+       /* Next display any multi language specific options.  */
+       print_specific_help (0, undoc_mask, all_langs_mask);
+       /* Then display any remaining, non-language options.  */
+       for (i = CL_MIN_OPTION_CLASS; i <= CL_MAX_OPTION_CLASS; i <<= 1)
+         print_specific_help (i, undoc_mask, 0);
+       exit_after_options = true;
+       break;
+      }
+
+    case OPT_ftarget_help:
     case OPT__target_help:
-      display_target_options ();
+      print_specific_help (CL_TARGET, CL_UNDOCUMENTED, 0);
       exit_after_options = true;
+
+      /* Allow the target a chance to give the user some additional information.  */
+      if (targetm.target_help)
+       targetm.target_help ();
       break;
 
+    case OPT_fhelp_:
+    case OPT__help_:
+      {
+       const char * a = arg;
+       unsigned int include_flags = 0;
+       /* Note - by default we include undocumented options when listing
+          specific classes.  If you only want to see documented options
+          then add ",^undocumented" to the --help= option.  e.g.:
+
+          --help=target,^undocumented  */
+       unsigned int exclude_flags = 0;
+
+       /* Walk along the argument string, parsing each word in turn.
+          The format is:
+          arg = [^]{word}[,{arg}]
+          word = {optimizers|target|warnings|undocumented|
+                  params|common|<language>}  */
+       while (* a != 0)
+         {
+           static struct
+           {
+             const char * string;
+             unsigned int flag;
+           }
+           specifics[] =
+           {
+             { "optimizers", CL_OPTIMIZATION },
+             { "target", CL_TARGET },
+             { "warnings", CL_WARNING },
+             { "undocumented", CL_UNDOCUMENTED },
+             { "params", CL_PARAMS },
+             { "joined", CL_JOINED },
+             { "separate", CL_SEPARATE },
+             { "common", CL_COMMON },
+             { NULL, 0 }
+           };
+           unsigned int * pflags;
+           char * comma;
+           unsigned int lang_flag, specific_flag;
+           unsigned int len;
+           unsigned int i;
+
+           if (* a == '^')
+             {
+               ++ a;
+               pflags = & exclude_flags;
+             }
+           else
+             pflags = & include_flags;
+
+           comma = strchr (a, ',');
+           if (comma == NULL)
+             len = strlen (a);
+           else
+             len = comma - a;
+
+           /* Check to see if the string matches an option class name.  */
+           for (i = 0, specific_flag = 0; specifics[i].string != NULL; i++)
+             if (strncasecmp (a, specifics[i].string, len) == 0)
+               {
+                 specific_flag = specifics[i].flag;
+                 break;
+               }
+           
+           /* Check to see if the string matches a language name.
+              Note - we rely upon the alpha-sorted nature of the entries in
+              the lang_names array, specifically that shorter names appear
+              before their longer variants.  (ie C before C++).  That way
+              when we are attempting to match --help=c for example we will
+              match with C first and not C++.  */
+           for (i = 0, lang_flag = 0; i < cl_lang_count; i++)
+             if (strncasecmp (a, lang_names[i], len) == 0)
+               {
+                 lang_flag = 1U << i;
+                 break;
+               }
+
+           if (specific_flag != 0)
+             {
+               if (lang_flag == 0)
+                 * pflags |= specific_flag;
+               else
+                 {
+                   /* The option's argument matches both the start of a
+                      language name and the start of an option class name.
+                      We have a special case for when the user has
+                      specified "--help=c", but otherwise we have to issue
+                      a warning.  */
+                   if (strncasecmp (a, "c", len) == 0)
+                     * pflags |= lang_flag;
+                   else
+                     fnotice (stderr,
+                              "warning: --help argument %.*s is ambiguous, please be more specific\n",
+                              len, a);
+                 }
+             }
+           else if (lang_flag != 0)
+             * pflags |= lang_flag;
+           else
+             fnotice (stderr,
+                      "warning: unrecognized argument to --help= option: %.*s\n",
+                      len, a);
+
+           if (comma == NULL)
+             break;
+           a = comma + 1;
+         }
+
+       if (include_flags)
+         print_specific_help (include_flags, exclude_flags, 0);
+       exit_after_options = true;
+       break;
+      }
+
     case OPT__version:
       print_version (stderr, "");
       exit_after_options = true;
@@ -708,20 +1532,47 @@ common_handle_option (size_t scode, const char *arg, int value)
       set_Wextra (value);
       break;
 
+    case OPT_Werror_:
+      enable_warning_as_error (arg, value, lang_mask);
+      break;
+
     case OPT_Wextra:
       set_Wextra (value);
       break;
 
     case OPT_Wlarger_than_:
+      /* This form corresponds to -Wlarger-than-.  
+        Kept for backward compatibility. 
+        Don't use it as the first argument of warning().  */
+
+    case OPT_Wlarger_than_eq:
       larger_than_size = value;
       warn_larger_than = value != -1;
       break;
 
+    case OPT_Wframe_larger_than_:
+      frame_larger_than_size = value;
+      warn_frame_larger_than = value != -1;
+      break;
+
     case OPT_Wstrict_aliasing:
+      set_Wstrict_aliasing (value);
+      break;
+
     case OPT_Wstrict_aliasing_:
       warn_strict_aliasing = value;
       break;
 
+    case OPT_Wstrict_overflow:
+      warn_strict_overflow = (value
+                             ? (int) WARN_STRICT_OVERFLOW_CONDITIONAL
+                             : 0);
+      break;
+
+    case OPT_Wstrict_overflow_:
+      warn_strict_overflow = value;
+      break;
+
     case OPT_Wunused:
       set_Wunused (value);
       break;
@@ -781,6 +1632,18 @@ common_handle_option (size_t scode, const char *arg, int value)
       fix_register (arg, 0, 0);
       break;
 
+    case OPT_fdbg_cnt_:
+      dbg_cnt_process_opt (arg);
+      break;
+
+    case OPT_fdbg_cnt_list:
+      dbg_cnt_list_all_counters ();
+      break;
+
+    case OPT_fdebug_prefix_map_:
+      add_debug_prefix_map (arg);
+      break;
+
     case OPT_fdiagnostics_show_location_:
       if (!strcmp (arg, "once"))
        diagnostic_prefixing_rule (global_dc) = DIAGNOSTICS_SHOW_PREFIX_ONCE;
@@ -791,6 +1654,10 @@ common_handle_option (size_t scode, const char *arg, int value)
        return 0;
       break;
 
+    case OPT_fdiagnostics_show_option:
+      global_dc->show_option_requested = true;
+      break;
+
     case OPT_fdump_:
       if (!dump_switch_p (arg))
        return 0;
@@ -800,6 +1667,10 @@ common_handle_option (size_t scode, const char *arg, int value)
       set_fast_math_flags (value);
       break;
 
+    case OPT_funsafe_math_optimizations:
+      set_unsafe_math_optimizations_flags (value);
+      break;
+
     case OPT_ffixed_:
       fix_register (arg, 1, 1);
       break;
@@ -808,7 +1679,16 @@ common_handle_option (size_t scode, const char *arg, int value)
     case OPT_finline_limit_eq:
       set_param_value ("max-inline-insns-single", value / 2);
       set_param_value ("max-inline-insns-auto", value / 2);
-      set_param_value ("max-inline-insns-rtl", value);
+      break;
+
+    case OPT_finstrument_functions_exclude_function_list_:
+      add_instrument_functions_exclude_list
+       (&flag_instrument_functions_exclude_functions, arg);
+      break;
+
+    case OPT_finstrument_functions_exclude_file_list_:
+      add_instrument_functions_exclude_list
+       (&flag_instrument_functions_exclude_files, arg);
       break;
 
     case OPT_fmessage_length_:
@@ -817,7 +1697,7 @@ common_handle_option (size_t scode, const char *arg, int value)
 
     case OPT_fpack_struct_:
       if (value <= 0 || (value & (value - 1)) || value > 16)
-       error("structure alignment must be a small power of two, not %d", value);
+       error ("structure alignment must be a small power of two, not %d", value);
       else
        {
          initial_max_fld_align = value;
@@ -833,6 +1713,19 @@ common_handle_option (size_t scode, const char *arg, int value)
       profile_arc_flag_set = true;
       break;
 
+    case OPT_finline_functions:
+      flag_inline_functions_set = true;
+      break;
+
+    case OPT_fprofile_dir_:
+      profile_data_prefix = xstrdup (arg);
+      break;
+
+    case OPT_fprofile_use_:
+      profile_data_prefix = xstrdup (arg);
+      flag_profile_use = true;
+      value = true;
+      /* No break here - do -fprofile-use processing. */
     case OPT_fprofile_use:
       if (!flag_branch_probabilities_set)
         flag_branch_probabilities = value;
@@ -846,12 +1739,14 @@ common_handle_option (size_t scode, const char *arg, int value)
         flag_tracer = value;
       if (!flag_value_profile_transformations_set)
         flag_value_profile_transformations = value;
-#ifdef HAVE_prefetch
-      if (0 && !flag_speculative_prefetching_set)
-       flag_speculative_prefetching = value;
-#endif
+      if (!flag_inline_functions_set)
+        flag_inline_functions = value;
       break;
 
+    case OPT_fprofile_generate_:
+      profile_data_prefix = xstrdup (arg);
+      value = true;
+      /* No break here - do -fprofile-generate processing. */
     case OPT_fprofile_generate:
       if (!profile_arc_flag_set)
         profile_arc_flag = value;
@@ -859,12 +1754,8 @@ common_handle_option (size_t scode, const char *arg, int value)
         flag_profile_values = value;
       if (!flag_value_profile_transformations_set)
         flag_value_profile_transformations = value;
-      if (!flag_unroll_loops_set)
-       flag_unroll_loops = value;
-#ifdef HAVE_prefetch
-      if (0 && !flag_speculative_prefetching_set)
-       flag_speculative_prefetching = value;
-#endif
+      if (!flag_inline_functions_set)
+        flag_inline_functions = value;
       break;
 
     case OPT_fprofile_values:
@@ -882,7 +1773,7 @@ common_handle_option (size_t scode, const char *arg, int value)
         else if (!strcmp(arg, "protected"))
           default_visibility = VISIBILITY_PROTECTED;
         else
-          error ("unrecognised visibility value \"%s\"", arg);
+          error ("unrecognized visibility value \"%s\"", arg);
       }
       break;
 
@@ -890,19 +1781,15 @@ common_handle_option (size_t scode, const char *arg, int value)
       flag_value_profile_transformations_set = true;
       break;
 
-    case OPT_fspeculative_prefetching:
-      flag_speculative_prefetching_set = true;
-      break;
-
     case OPT_frandom_seed:
       /* The real switch is -fno-random-seed.  */
       if (value)
        return 0;
-      flag_random_seed = NULL;
+      set_random_seed (NULL);
       break;
 
     case OPT_frandom_seed_:
-      flag_random_seed = arg;
+      set_random_seed (arg);
       break;
 
     case OPT_fsched_verbose_:
@@ -944,6 +1831,10 @@ common_handle_option (size_t scode, const char *arg, int value)
       stack_limit_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (arg));
       break;
 
+    case OPT_ftree_vectorizer_verbose_:
+      vect_set_verbosity_level (arg);
+      break;
+
     case OPT_ftls_model_:
       if (!strcmp (arg, "global-dynamic"))
        flag_tls_default = TLS_MODEL_GLOBAL_DYNAMIC;
@@ -954,7 +1845,7 @@ common_handle_option (size_t scode, const char *arg, int value)
       else if (!strcmp (arg, "local-exec"))
        flag_tls_default = TLS_MODEL_LOCAL_EXEC;
       else
-       warning ("unknown tls-model \"%s\"", arg);
+       warning (0, "unknown tls-model \"%s\"", arg);
       break;
 
     case OPT_ftracer:
@@ -995,10 +1886,6 @@ common_handle_option (size_t scode, const char *arg, int value)
       set_debug_level (XCOFF_DEBUG, code == OPT_gxcoff_, arg);
       break;
 
-    case OPT_m:
-      set_target_switch (arg);
-      break;
-
     case OPT_o:
       asm_file_name = arg;
       break;
@@ -1007,13 +1894,20 @@ common_handle_option (size_t scode, const char *arg, int value)
       flag_pedantic_errors = pedantic = 1;
       break;
 
+    case OPT_floop_optimize:
+    case OPT_frerun_loop_opt:
+    case OPT_fstrength_reduce:
+    case OPT_ftree_store_copy_prop:
+    case OPT_fforce_addr:
+    case OPT_ftree_salias:
+      /* These are no-ops, preserved for backward compatibility.  */
+      break;
+
     default:
       /* If the flag was handled in a standard way, assume the lack of
         processing here is intentional.  */
-      if (cl_options[scode].flag_var)
-       break;
-
-      abort ();
+      gcc_assert (cl_options[scode].flag_var);
+      break;
     }
 
   return 1;
@@ -1034,7 +1928,7 @@ handle_param (const char *carg)
     {
       value = integral_argument (equal + 1);
       if (value == -1)
-       error ("invalid --param value `%s'", equal + 1);
+       error ("invalid --param value %qs", equal + 1);
       else
        {
          *equal = '\0';
@@ -1050,7 +1944,6 @@ static void
 set_Wextra (int setting)
 {
   extra_warnings = setting;
-  warn_unused_value = setting;
   warn_unused_parameter = (setting && maybe_warn_unused_parameter);
 
   /* We save the value of warn_uninitialized, since if they put
@@ -1079,22 +1972,50 @@ set_Wunused (int setting)
   warn_unused_value = setting;
 }
 
+/* Used to set the level of strict aliasing warnings, 
+   when no level is specified (i.e., when -Wstrict-aliasing, and not
+   -Wstrict-aliasing=level was given).
+   ONOFF is assumed to take value 1 when -Wstrict-aliasing is specified,
+   and 0 otherwise.  After calling this function, wstrict_aliasing will be
+   set to the default value of -Wstrict_aliasing=level, currently 3.  */
+void
+set_Wstrict_aliasing (int onoff)
+{
+  gcc_assert (onoff == 0 || onoff == 1);
+  if (onoff != 0)
+    warn_strict_aliasing = 3;
+  else
+    warn_strict_aliasing = 0;
+}
+
 /* The following routines are useful in setting all the flags that
    -ffast-math and -fno-fast-math imply.  */
 void
 set_fast_math_flags (int set)
 {
-  flag_trapping_math = !set;
   flag_unsafe_math_optimizations = set;
+  set_unsafe_math_optimizations_flags (set);
   flag_finite_math_only = set;
   flag_errno_math = !set;
   if (set)
     {
       flag_signaling_nans = 0;
       flag_rounding_math = 0;
+      flag_cx_limited_range = 1;
     }
 }
 
+/* When -funsafe-math-optimizations is set the following 
+   flags are set as well.  */ 
+void
+set_unsafe_math_optimizations_flags (int set)
+{
+  flag_trapping_math = !set;
+  flag_signed_zeros = !set;
+  flag_associative_math = set;
+  flag_reciprocal_math = set;
+}
+
 /* Return true iff flags are set as if -ffast-math.  */
 bool
 fast_math_flags_set_p (void)
@@ -1102,6 +2023,7 @@ fast_math_flags_set_p (void)
   return (!flag_trapping_math
          && flag_unsafe_math_optimizations
          && flag_finite_math_only
+         && !flag_signed_zeros
          && !flag_errno_math);
 }
 
@@ -1130,7 +2052,7 @@ set_debug_level (enum debug_info_type type, int extended, const char *arg)
            }
 
          if (write_symbols == NO_DEBUG)
-           warning ("target system does not support debug output");
+           warning (0, "target system does not support debug output");
        }
     }
   else
@@ -1159,214 +2081,96 @@ set_debug_level (enum debug_info_type type, int extended, const char *arg)
     }
 }
 
-/* Output --help text.  */
-static void
-print_help (void)
-{
-  size_t i;
-  const char *p;
-
-  GET_ENVIRONMENT (p, "COLUMNS");
-  if (p)
-    {
-      int value = atoi (p);
-      if (value > 0)
-       columns = value;
-    }
-
-  puts (_("The following options are language-independent:\n"));
-
-  print_filtered_help (CL_COMMON);
-  print_param_help ();
-
-  for (i = 0; lang_names[i]; i++)
-    {
-      printf (_("The %s front end recognizes the following options:\n\n"),
-             lang_names[i]);
-      print_filtered_help (1U << i);
-    }
-
-  display_target_options ();
-}
+/* Return 1 if OPTION is enabled, 0 if it is disabled, or -1 if it isn't
+   a simple on-off switch.  */
 
-/* Print the help for --param.  */
-static void
-print_param_help (void)
+int
+option_enabled (int opt_idx)
 {
-  size_t i;
-
-  puts (_("The --param option recognizes the following as parameters:\n"));
+  const struct cl_option *option = &(cl_options[opt_idx]);
 
-  for (i = 0; i < LAST_PARAM; i++)
-    {
-      const char *help = compiler_params[i].help;
-      const char *param = compiler_params[i].option;
+  if (option->flag_var)
+    switch (option->var_type)
+      {
+      case CLVC_BOOLEAN:
+       return *(int *) option->flag_var != 0;
 
-      if (help == NULL || *help == '\0')
-       help = undocumented_msg;
+      case CLVC_EQUAL:
+       return *(int *) option->flag_var == option->var_value;
 
-      /* Get the translation.  */
-      help = _(help);
+      case CLVC_BIT_CLEAR:
+       return (*(int *) option->flag_var & option->var_value) == 0;
 
-      wrap_help (help, param, strlen (param));
-    }
+      case CLVC_BIT_SET:
+       return (*(int *) option->flag_var & option->var_value) != 0;
 
-  putchar ('\n');
+      case CLVC_STRING:
+       break;
+      }
+  return -1;
 }
 
-/* Print help for a specific front-end, etc.  */
-static void
-print_filtered_help (unsigned int flag)
-{
-  unsigned int i, len, filter, indent = 0;
-  bool duplicates = false;
-  const char *help, *opt, *tab;
-  static char *printed;
-
-  if (flag == CL_COMMON)
-    {
-      filter = flag;
-      if (!printed)
-       printed = xmalloc (cl_options_count);
-      memset (printed, 0, cl_options_count);
-    }
-  else
-    {
-      /* Don't print COMMON options twice.  */
-      filter = flag | CL_COMMON;
-
-      for (i = 0; i < cl_options_count; i++)
-       {
-         if ((cl_options[i].flags & filter) != flag)
-           continue;
-
-         /* Skip help for internal switches.  */
-         if (cl_options[i].flags & CL_UNDOCUMENTED)
-           continue;
-
-         /* Skip switches that have already been printed, mark them to be
-            listed later.  */
-         if (printed[i])
-           {
-             duplicates = true;
-             indent = print_switch (cl_options[i].opt_text, indent);
-           }
-       }
+/* Fill STATE with the current state of option OPTION.  Return true if
+   there is some state to store.  */
 
-      if (duplicates)
-       {
-         putchar ('\n');
-         putchar ('\n');
-       }
-    }
+bool
+get_option_state (int option, struct cl_option_state *state)
+{
+  if (cl_options[option].flag_var == 0)
+    return false;
 
-  for (i = 0; i < cl_options_count; i++)
+  switch (cl_options[option].var_type)
     {
-      if ((cl_options[i].flags & filter) != flag)
-       continue;
-
-      /* Skip help for internal switches.  */
-      if (cl_options[i].flags & CL_UNDOCUMENTED)
-       continue;
-
-      /* Skip switches that have already been printed.  */
-      if (printed[i])
-       continue;
-
-      printed[i] = true;
-
-      help = cl_options[i].help;
-      if (!help)
-       help = undocumented_msg;
-
-      /* Get the translation.  */
-      help = _(help);
+    case CLVC_BOOLEAN:
+    case CLVC_EQUAL:
+      state->data = cl_options[option].flag_var;
+      state->size = sizeof (int);
+      break;
 
-      tab = strchr (help, '\t');
-      if (tab)
-       {
-         len = tab - help;
-         opt = help;
-         help = tab + 1;
-       }
-      else
-       {
-         opt = cl_options[i].opt_text;
-         len = strlen (opt);
-       }
+    case CLVC_BIT_CLEAR:
+    case CLVC_BIT_SET:
+      state->ch = option_enabled (option);
+      state->data = &state->ch;
+      state->size = 1;
+      break;
 
-      wrap_help (help, opt, len);
+    case CLVC_STRING:
+      state->data = *(const char **) cl_options[option].flag_var;
+      if (state->data == 0)
+       state->data = "";
+      state->size = strlen (state->data) + 1;
+      break;
     }
-
-  putchar ('\n');
+  return true;
 }
 
-/* Output ITEM, of length ITEM_WIDTH, in the left column, followed by
-   word-wrapped HELP in a second column.  */
-static unsigned int
-print_switch (const char *text, unsigned int indent)
-{
-  unsigned int len = strlen (text) + 1; /* trailing comma */
+/* Enable a warning option as an error.  This is used by -Werror= and
+   also by legacy Werror-implicit-function-declaration.  */
 
-  if (indent)
+void
+enable_warning_as_error (const char *arg, int value, unsigned int lang_mask)
+{
+  char *new_option;
+  int option_index;
+
+  new_option = XNEWVEC (char, strlen (arg) + 2);
+  new_option[0] = 'W';
+  strcpy (new_option + 1, arg);
+  option_index = find_opt (new_option, lang_mask);
+  if (option_index == N_OPTS)
     {
-      putchar (',');
-      if (indent + len > columns)
-       {
-         putchar ('\n');
-         putchar (' ');
-         indent = 1;
-       }
+      error ("-Werror=%s: No option -%s", arg, new_option);
     }
   else
-    putchar (' ');
-
-  putchar (' ');
-  fputs (text, stdout);
-
-  return indent + len + 1;
-}
-
-/* Output ITEM, of length ITEM_WIDTH, in the left column, followed by
-   word-wrapped HELP in a second column.  */
-static void
-wrap_help (const char *help, const char *item, unsigned int item_width)
-{
-  unsigned int col_width = 27;
-  unsigned int remaining, room, len;
-
-  remaining = strlen (help);
-
-  do
     {
-      room = columns - 3 - MAX (col_width, item_width);
-      if (room > columns)
-       room = 0;
-      len = remaining;
-
-      if (room < len)
-       {
-         unsigned int i;
-
-         for (i = 0; help[i]; i++)
-           {
-             if (i >= room && len != remaining)
-               break;
-             if (help[i] == ' ')
-               len = i;
-             else if ((help[i] == '-' || help[i] == '/')
-                      && help[i + 1] != ' '
-                      && i > 0 && ISALPHA (help[i - 1]))
-               len = i + 1;
-           }
-       }
-
-      printf( "  %-*.*s %.*s\n", col_width, item_width, item, len, help);
-      item_width = 0;
-      while (help[len] == ' ')
-       len++;
-      help += len;
-      remaining -= len;
+      int kind = value ? DK_ERROR : DK_WARNING;
+      diagnostic_classify_diagnostic (global_dc, option_index, kind);
+      
+      /* -Werror=foo implies -Wfoo.  */
+      if (cl_options[option_index].var_type == CLVC_BOOLEAN
+         && cl_options[option_index].flag_var
+         && kind == DK_ERROR)
+       *(int *) cl_options[option_index].flag_var = 1;
     }
-  while (remaining);
+  free (new_option);
 }