OSDN Git Service

2009-04-10 H.J. Lu <hongjiu.lu@intel.com>
[pf3gnuchains/gcc-fork.git] / gcc / opts.c
index bbce074..76f5d1e 100644 (file)
@@ -1,12 +1,13 @@
 /* Command line option handling.
-   Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   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, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -26,6 +26,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "tm.h"
 #include "tree.h"
 #include "rtl.h"
+#include "expr.h"
 #include "ggc.h"
 #include "output.h"
 #include "langhooks.h"
@@ -39,11 +40,16 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #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;
 bool g_switch_set;
 
+/* Same for selective scheduling.  */
+bool sel_sched_switch_set;
+
 /* True if we should exit after parsing options.  */
 bool exit_after_options;
 
@@ -56,12 +62,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;
-
-/* Hack for cooperation between set_Wunused and set_Wextra.  */
-static bool maybe_warn_unused_parameter;
+/* 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;
 
 /* Type(s) of debugging information we are producing (if any).  See
    flags.h for the definitions of the different possible types of
@@ -72,6 +76,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.  */
@@ -80,19 +334,15 @@ 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.  */
@@ -100,6 +350,23 @@ 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;
 static bool flag_peel_loops_set, flag_branch_probabilities_set;
+static bool flag_inline_functions_set, flag_ipa_cp_set, flag_ipa_cp_clone_set;
+static bool flag_predictive_commoning_set, flag_unswitch_loops_set, flag_gcse_after_reload_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;
@@ -114,12 +381,6 @@ 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_target_help (void);
-static void print_help (void);
-static void print_param_help (void);
-static void print_filtered_help (unsigned int);
-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);
 
@@ -185,6 +446,36 @@ complain_wrong_lang (const char *text, const struct cl_option *option,
   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.
+   Note that if we do complain, it is only as a warning, not an error;
+   passing the compiler an unrecognised -Wno-* option should never
+   change whether the compilation succeeds or fails.  */
+
+static void postpone_unknown_option_warning(const char *opt)
+{
+  VEC_safe_push (const_char_p, heap, ignored_options, opt);
+}
+
+/* Produce a warning 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);
+      warning (0, "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
@@ -214,6 +505,14 @@ handle_option (const char **argv, unsigned int lang_mask)
       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 warnings for unknown -Wno-* options
+             unless we issue diagnostics.  */
+         postpone_unknown_option_warning (argv[0]);
+         result = 1;
+         goto done;
+       }
     }
 
   if (opt_index == cl_options_count)
@@ -272,6 +571,15 @@ handle_option (const char **argv, unsigned int lang_mask)
       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)))
     {
@@ -319,7 +627,7 @@ handle_option (const char **argv, unsigned int lang_mask)
        *(const char **) option->flag_var = arg;
        break;
       }
-  
+
   if (option->flags & lang_mask)
     if (lang_hooks.handle_option (opt_index, arg, value) == 0)
       result = 0;
@@ -343,10 +651,90 @@ 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 = XRESIZEVEC (const char *, in_fnames, num_in_fnames);
   in_fnames[num_in_fnames - 1] = filename;
 }
 
+/* Add comma-separated strings to a char_p vector.  */
+
+static void
+add_comma_separated_to_vector (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.  */
@@ -363,7 +751,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;
@@ -384,12 +776,35 @@ handle_options (unsigned int argc, const char **argv, unsigned int lang_mask)
 void
 decode_options (unsigned int argc, const char **argv)
 {
-  unsigned int i, lang_mask;
+  static bool first_time_p = true;
+  static int initial_min_crossjump_insns;
+  static int initial_max_fields_for_field_sensitive;
+  static int initial_loop_invariant_max_bbs_in_loop;
+  static unsigned int initial_lang_mask;
 
-  /* Perform language-specific options initialization.  */
-  lang_mask = lang_hooks.init_options (argc, argv);
+  unsigned int i, lang_mask;
+  int opt1;
+  int opt2;
+  int opt3;
+  int opt1_max;
 
-  lang_hooks.initialize_diagnostics (global_dc);
+  if (first_time_p)
+    {
+      /* Perform language-specific options initialization.  */
+      initial_lang_mask = lang_mask = lang_hooks.init_options (argc, argv);
+
+      lang_hooks.initialize_diagnostics (global_dc);
+
+      /* Save initial values of parameters we reset.  */
+      initial_min_crossjump_insns
+       = compiler_params[PARAM_MIN_CROSSJUMP_INSNS].value;
+      initial_max_fields_for_field_sensitive
+       = compiler_params[PARAM_MAX_FIELDS_FOR_FIELD_SENSITIVE].value;
+      initial_loop_invariant_max_bbs_in_loop
+       = compiler_params[PARAM_LOOP_INVARIANT_MAX_BBS_IN_LOOP].value;
+    }
+  else
+    lang_mask = initial_lang_mask;
 
   /* Scan to see what optimization level has been specified.  That will
      determine the default value of many flags.  */
@@ -423,132 +838,128 @@ decode_options (unsigned int argc, const char **argv)
            }
        }
     }
-
-  if (!optimize)
-    {
-      flag_merge_constants = 0;
-    }
-
-  if (optimize >= 1)
-    {
-      flag_defer_pop = 1;
+  
+  /* Use priority coloring if cover classes is not defined for the
+     target.  */
+  if (targetm.ira_cover_classes == NULL)
+    flag_ira_algorithm = IRA_ALGORITHM_PRIORITY;
+
+  /* -O1 optimizations.  */
+  opt1 = (optimize >= 1);
+  flag_defer_pop = opt1;
 #ifdef DELAY_SLOTS
-      flag_delayed_branch = 1;
+  flag_delayed_branch = opt1;
 #endif
 #ifdef CAN_DEBUG_WITHOUT_FP
-      flag_omit_frame_pointer = 1;
+  flag_omit_frame_pointer = opt1;
 #endif
-      flag_guess_branch_prob = 1;
-      flag_cprop_registers = 1;
-      flag_if_conversion = 1;
-      flag_if_conversion2 = 1;
-      flag_ipa_pure_const = 1;
-      flag_ipa_reference = 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;
-      flag_tree_salias = 1;
-      if (!no_unit_at_a_time_default)
-        flag_unit_at_a_time = 1;
-
-      if (!optimize_size)
-       {
-         /* Loop header copying usually increases size of the code.  This used
-            not to be true, since quite often it is possible to verify that
-            the condition is satisfied in the first iteration and therefore
-            to eliminate it.  Jump threading handles these cases now.  */
-         flag_tree_ch = 1;
-       }
-    }
-
-  if (optimize >= 2)
-    {
-      flag_thread_jumps = 1;
-      flag_crossjumping = 1;
-      flag_optimize_sibling_calls = 1;
-      flag_cse_follow_jumps = 1;
-      flag_gcse = 1;
-      flag_expensive_optimizations = 1;
-      flag_ipa_type_escape = 1;
-      flag_rerun_cse_after_loop = 1;
-      flag_caller_saves = 1;
-      flag_peephole2 = 1;
+  flag_guess_branch_prob = opt1;
+  flag_cprop_registers = opt1;
+  flag_if_conversion = opt1;
+  flag_if_conversion2 = opt1;
+  flag_ipa_pure_const = opt1;
+  flag_ipa_reference = opt1;
+  flag_merge_constants = opt1;
+  flag_split_wide_types = opt1;
+  flag_tree_ccp = opt1;
+  flag_tree_dce = opt1;
+  flag_tree_dom = opt1;
+  flag_tree_dse = opt1;
+  flag_tree_ter = opt1;
+  flag_tree_sra = opt1;
+  flag_tree_copyrename = opt1;
+  flag_tree_fre = opt1;
+  flag_tree_copy_prop = opt1;
+  flag_tree_sink = opt1;
+  flag_tree_ch = opt1;
+
+  /* -O2 optimizations.  */
+  opt2 = (optimize >= 2);
+  flag_inline_small_functions = opt2;
+  flag_indirect_inlining = opt2;
+  flag_thread_jumps = opt2;
+  flag_crossjumping = opt2;
+  flag_optimize_sibling_calls = opt2;
+  flag_forward_propagate = opt2;
+  flag_cse_follow_jumps = opt2;
+  flag_gcse = opt2;
+  flag_expensive_optimizations = opt2;
+  flag_rerun_cse_after_loop = opt2;
+  flag_caller_saves = opt2;
+  flag_peephole2 = opt2;
 #ifdef INSN_SCHEDULING
-      flag_schedule_insns = 1;
-      flag_schedule_insns_after_reload = 1;
+  flag_schedule_insns = opt2;
+  flag_schedule_insns_after_reload = opt2;
 #endif
-      flag_regmove = 1;
-      flag_strict_aliasing = 1;
-      flag_delete_null_pointer_checks = 1;
-      flag_reorder_blocks = 1;
-      flag_reorder_functions = 1;
-      flag_tree_store_ccp = 1;
-      flag_tree_store_copy_prop = 1;
-      flag_tree_vrp = 1;
-
-      if (!optimize_size)
-       {
-          /* PRE tends to generate bigger code.  */
-          flag_tree_pre = 1;
-       }
-    }
-
-  if (optimize >= 3)
-    {
-      flag_inline_functions = 1;
-      flag_unswitch_loops = 1;
-      flag_gcse_after_reload = 1;
-    }
-
-  if (optimize < 2 || optimize_size)
-    {
-      align_loops = 1;
-      align_jumps = 1;
-      align_labels = 1;
-      align_functions = 1;
-
-      /* Don't reorder blocks when optimizing for size because extra
-        jump insns may be created; also barrier may create extra padding.
-
-        More correctly we should have a block reordering mode that tried
-        to minimize the combined size of all the jumps.  This would more
-        or less automatically remove extra jumps, but would also try to
-        use more short jumps instead of long jumps.  */
-      flag_reorder_blocks = 0;
-      flag_reorder_blocks_and_partition = 0;
-    }
+  flag_regmove = opt2;
+  flag_strict_aliasing = opt2;
+  flag_strict_overflow = opt2;
+  flag_reorder_blocks = opt2;
+  flag_reorder_functions = opt2;
+  flag_tree_vrp = opt2;
+  flag_tree_builtin_call_dce = opt2;
+  flag_tree_pre = opt2;
+  flag_tree_switch_conversion = 1;
+  flag_ipa_cp = opt2;
+
+  /* Track fields in field-sensitive alias analysis.  */
+  set_param_value ("max-fields-for-field-sensitive",
+                  (opt2) ? 100 : initial_max_fields_for_field_sensitive);
+
+  /* For -O1 only do loop invariant motion for very small loops.  */
+  set_param_value ("loop-invariant-max-bbs-in-loop",
+                  (opt2) ? initial_loop_invariant_max_bbs_in_loop : 1000);
+
+  /* -O3 optimizations.  */
+  opt3 = (optimize >= 3);
+  flag_predictive_commoning = opt3;
+  flag_inline_functions = opt3;
+  flag_unswitch_loops = opt3;
+  flag_gcse_after_reload = opt3;
+  flag_tree_vectorize = opt3;
+  flag_ipa_cp_clone = opt3;
+  if (flag_ipa_cp_clone)
+    flag_ipa_cp = 1;
+
+  /* Just -O1/-O0 optimizations.  */
+  opt1_max = (optimize <= 1);
+  align_loops = opt1_max;
+  align_jumps = opt1_max;
+  align_labels = opt1_max;
+  align_functions = opt1_max;
 
   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);
+      /* Inlining of functions reducing size is a good idea regardless of them
+        being declared inline.  */
       flag_inline_functions = 1;
 
+      /* Basic optimization options.  */
+      optimize_size = 1;
+      if (optimize > 2)
+       optimize = 2;
+
       /* We want to crossjump as much as possible.  */
       set_param_value ("min-crossjump-insns", 1);
     }
+  else
+    set_param_value ("min-crossjump-insns", initial_min_crossjump_insns);
 
-  /* Initialize whether `char' is signed.  */
-  flag_signed_char = DEFAULT_SIGNED_CHAR;
-  /* Set this to a special "uninitialized" value.  The actual default is set
-     after target options have been processed.  */
-  flag_short_enums = 2;
-
-  /* Initialize target_flags before OPTIMIZATION_OPTIONS so the latter can
-     modify it.  */
-  target_flags = targetm.default_target_flags;
-
-  /* Some tagets have ABI-specified unwind tables.  */
-  flag_unwind_tables = targetm.unwind_tables_default;
+  if (first_time_p)
+    {
+      /* Initialize whether `char' is signed.  */
+      flag_signed_char = DEFAULT_SIGNED_CHAR;
+      /* Set this to a special "uninitialized" value.  The actual default is
+        set after target options have been processed.  */
+      flag_short_enums = 2;
+
+      /* Initialize target_flags before OPTIMIZATION_OPTIONS so the latter can
+        modify it.  */
+      target_flags = targetm.default_target_flags;
+
+      /* Some targets 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.  */
@@ -557,39 +968,51 @@ 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;
+  /* Handle related options for unit-at-a-time, toplevel-reorder, and
+     section-anchors.  */
+  if (!flag_unit_at_a_time)
+    {
+      if (flag_section_anchors == 1)
+       error ("Section anchors must be disabled when unit-at-a-time "
+              "is disabled.");
+      flag_section_anchors = 0;
+      if (flag_toplevel_reorder == 1)
+       error ("Toplevel reorder must be disabled when unit-at-a-time "
+              "is disabled.");
+      flag_toplevel_reorder = 0;
+    }
+  /* Unless the user has asked for section anchors, we disable toplevel
+     reordering at -O0 to disable transformations that might be surprising
+     to end users and to get -fno-toplevel-reorder tested.  */
+  if (!optimize && flag_toplevel_reorder == 2 && flag_section_anchors != 1)
+    {
+      flag_toplevel_reorder = 0;
+      flag_section_anchors = 0;
+    }
+  if (!flag_toplevel_reorder)
+    {
+      if (flag_section_anchors == 1)
+       error ("section anchors must be disabled when toplevel reorder"
+              " is disabled");
+      flag_section_anchors = 0;
+    }
 
-  if (flag_no_inline == 2)
-    flag_no_inline = 0;
-  else
-    flag_really_no_inline = flag_no_inline;
+  if (first_time_p)
+    {
+      if (flag_pie)
+       flag_pic = flag_pie;
+      if (flag_pic && !flag_pie)
+       flag_shlib = 1;
+    }
 
-  /* 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");
+      flag_no_inline = 1;
     }
 
-  if (flag_really_no_inline == 2)
-    flag_really_no_inline = flag_no_inline;
-
   /* 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
@@ -598,8 +1021,8 @@ decode_options (unsigned int argc, const char **argv)
 
   if (flag_exceptions && flag_reorder_blocks_and_partition)
     {
-      inform 
-           ("-freorder-blocks-and-partition does not work with exceptions");
+      inform (input_location, 
+             "-freorder-blocks-and-partition does not work with exceptions");
       flag_reorder_blocks_and_partition = 0;
       flag_reorder_blocks = 1;
     }
@@ -610,7 +1033,7 @@ decode_options (unsigned int argc, const char **argv)
   if (flag_unwind_tables && ! targetm.unwind_tables_default
       && flag_reorder_blocks_and_partition)
     {
-      inform ("-freorder-blocks-and-partition does not support unwind info");
+      inform (input_location, "-freorder-blocks-and-partition does not support unwind info");
       flag_reorder_blocks_and_partition = 0;
       flag_reorder_blocks = 1;
     }
@@ -623,11 +1046,346 @@ decode_options (unsigned int argc, const char **argv)
       && (!targetm.have_named_sections
          || (flag_unwind_tables && targetm.unwind_tables_default)))
     {
-      inform 
-       ("-freorder-blocks-and-partition does not work on this architecture");
+      inform (input_location,
+             "-freorder-blocks-and-partition does not work on this architecture");
       flag_reorder_blocks_and_partition = 0;
       flag_reorder_blocks = 1;
     }
+
+  /* Pipelining of outer loops is only possible when general pipelining
+     capabilities are requested.  */
+  if (!flag_sel_sched_pipelining)
+    flag_sel_sched_pipelining_outer_loops = 0;
+
+  if (!targetm.ira_cover_classes
+      && flag_ira_algorithm == IRA_ALGORITHM_CB)
+    {
+      inform (input_location,
+             "-fira-algorithm=CB does not work on this architecture");
+      flag_ira_algorithm = IRA_ALGORITHM_PRIORITY;
+    }
+
+  /* Save the current optimization options if this is the first call.  */
+  if (first_time_p)
+    {
+      optimization_default_node = build_optimization_node ();
+      optimization_current_node = optimization_default_node;
+      first_time_p = false;
+    }
+  if (flag_conserve_stack)
+    {
+      if (!PARAM_SET_P (PARAM_LARGE_STACK_FRAME))
+        PARAM_VALUE (PARAM_LARGE_STACK_FRAME) = 100;
+      if (!PARAM_SET_P (PARAM_STACK_FRAME_GROWTH))
+        PARAM_VALUE (PARAM_STACK_FRAME_GROWTH) = 40;
+    }
+
+}
+
+#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 = XCNEWVAR (char, 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;
+
+  /* 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);
+
+  /* If we have not done so already, obtain
+     the desired maximum width of the output.  */
+  if (columns == 0)
+    {
+      const char *p;
+
+      GET_ENVIRONMENT (p, "COLUMNS");
+      if (p != NULL)
+       {
+         int value = atoi (p);
+
+         if (value > 0)
+           columns = value;
+       }
+
+      if (columns == 0)
+       /* Use a reasonable default.  */
+       columns = 80;
+    }
+
+  /* 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 ++)
+    {
+      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 & all_langs_mask)
+           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;
+       }
+    }
+
+  if (description == NULL)
+    {
+      if (any_flags == 0)
+       {
+         if (include_flags & CL_UNDOCUMENTED)
+           description = _("The following options are not documented");
+         else if (include_flags & CL_SEPARATE)
+           description = _("The following options take separate arguments");
+         else if (include_flags & CL_JOINED)
+           description = _("The following options take joined arguments");
+         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
@@ -639,24 +1397,169 @@ static int
 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:
-      print_target_help ();
+      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;
+           if (len == 0)
+             {
+               a = comma + 1;
+               continue;
+             }
+
+           /* 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.  (i.e. 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;
@@ -678,30 +1581,7 @@ common_handle_option (size_t scode, const char *arg, int value,
       break;
 
     case OPT_Werror_:
-      {
-       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)
-         {
-           error ("-Werror-%s: No option -%s", arg, new_option);
-         }
-       else
-         {
-           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;
-           free (new_option);
-         }
-      }
+      enable_warning_as_error (arg, value, lang_mask);
       break;
 
     case OPT_Wextra:
@@ -709,17 +1589,40 @@ common_handle_option (size_t scode, const char *arg, int 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);
+      warn_unused = value;
       break;
 
     case OPT_aux_info:
@@ -777,6 +1680,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;
@@ -796,10 +1711,23 @@ common_handle_option (size_t scode, const char *arg, int value,
        return 0;
       break;
 
+    case OPT_fexcess_precision_:
+      if (!strcmp (arg, "fast"))
+       flag_excess_precision_cmdline = EXCESS_PRECISION_FAST;
+      else if (!strcmp (arg, "standard"))
+       flag_excess_precision_cmdline = EXCESS_PRECISION_STANDARD;
+      else
+       error ("unknown excess precision style \"%s\"", arg);
+      break;
+
     case OPT_ffast_math:
       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;
@@ -810,13 +1738,23 @@ common_handle_option (size_t scode, const char *arg, int value,
       set_param_value ("max-inline-insns-auto", value / 2);
       break;
 
+    case OPT_finstrument_functions_exclude_function_list_:
+      add_comma_separated_to_vector
+       (&flag_instrument_functions_exclude_functions, arg);
+      break;
+
+    case OPT_finstrument_functions_exclude_file_list_:
+      add_comma_separated_to_vector
+       (&flag_instrument_functions_exclude_files, arg);
+      break;
+
     case OPT_fmessage_length_:
       pp_set_line_maximum_length (global_dc->printer, value);
       break;
 
     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;
@@ -832,6 +1770,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;
@@ -845,8 +1796,25 @@ 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;
-      break;
-
+      if (!flag_inline_functions_set)
+        flag_inline_functions = value;
+      if (!flag_ipa_cp_set)
+        flag_ipa_cp = value;
+      if (!flag_ipa_cp_clone_set
+         && value && flag_ipa_cp)
+       flag_ipa_cp_clone = value;
+      if (!flag_predictive_commoning_set)
+       flag_predictive_commoning = value;
+      if (!flag_unswitch_loops_set)
+       flag_unswitch_loops = value;
+      if (!flag_gcse_after_reload_set)
+       flag_gcse_after_reload = 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;
@@ -854,6 +1822,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_inline_functions_set)
+        flag_inline_functions = value;
       break;
 
     case OPT_fprofile_values:
@@ -883,11 +1853,16 @@ common_handle_option (size_t scode, const char *arg, int value,
       /* 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_fselective_scheduling:
+    case OPT_fselective_scheduling2:
+      sel_sched_switch_set = true;
       break;
 
     case OPT_fsched_verbose_:
@@ -908,6 +1883,37 @@ common_handle_option (size_t scode, const char *arg, int value,
       flag_sched_stalled_insns_dep = value;
       break;
 
+    case OPT_fstack_check_:
+      if (!strcmp (arg, "no"))
+       flag_stack_check = NO_STACK_CHECK;
+      else if (!strcmp (arg, "generic"))
+       /* This is the old stack checking method.  */
+       flag_stack_check = STACK_CHECK_BUILTIN
+                          ? FULL_BUILTIN_STACK_CHECK
+                          : GENERIC_STACK_CHECK;
+      else if (!strcmp (arg, "specific"))
+       /* This is the new stack checking method.  */
+       flag_stack_check = STACK_CHECK_BUILTIN
+                          ? FULL_BUILTIN_STACK_CHECK
+                          : STACK_CHECK_STATIC_BUILTIN
+                            ? STATIC_BUILTIN_STACK_CHECK
+                            : GENERIC_STACK_CHECK;
+      else
+       warning (0, "unknown stack check parameter \"%s\"", arg);
+      break;
+
+    case OPT_fstack_check:
+      /* This is the same as the "specific" mode above.  */
+      if (value)
+       flag_stack_check = STACK_CHECK_BUILTIN
+                          ? FULL_BUILTIN_STACK_CHECK
+                          : STACK_CHECK_STATIC_BUILTIN
+                            ? STATIC_BUILTIN_STACK_CHECK
+                            : GENERIC_STACK_CHECK;
+      else
+       flag_stack_check = NO_STACK_CHECK;
+      break;
+
     case OPT_fstack_limit:
       /* The real switch is -fno-stack-limit.  */
       if (value)
@@ -946,10 +1952,54 @@ common_handle_option (size_t scode, const char *arg, int value,
        warning (0, "unknown tls-model \"%s\"", arg);
       break;
 
+    case OPT_fira_algorithm_:
+      if (!strcmp (arg, "CB"))
+       flag_ira_algorithm = IRA_ALGORITHM_CB;
+      else if (!strcmp (arg, "priority"))
+       flag_ira_algorithm = IRA_ALGORITHM_PRIORITY;
+      else
+       warning (0, "unknown ira algorithm \"%s\"", arg);
+      break;
+
+    case OPT_fira_region_:
+      if (!strcmp (arg, "one"))
+       flag_ira_region = IRA_REGION_ONE;
+      else if (!strcmp (arg, "all"))
+       flag_ira_region = IRA_REGION_ALL;
+      else if (!strcmp (arg, "mixed"))
+       flag_ira_region = IRA_REGION_MIXED;
+      else
+       warning (0, "unknown ira region \"%s\"", arg);
+      break;
+
+    case OPT_fira_verbose_:
+      flag_ira_verbose = value;
+      break;
+
     case OPT_ftracer:
       flag_tracer_set = true;
       break;
 
+    case OPT_fipa_cp:
+      flag_ipa_cp_set = true;
+      break;
+
+    case OPT_fipa_cp_clone:
+      flag_ipa_cp_clone_set = true;
+      break;
+
+    case OPT_fpredictive_commoning:
+      flag_predictive_commoning_set = true;
+      break;
+
+    case OPT_funswitch_loops:
+      flag_unswitch_loops_set = true;
+      break;
+
+    case OPT_fgcse_after_reload:
+      flag_gcse_after_reload_set = true;
+      break;
+
     case OPT_funroll_loops:
       flag_unroll_loops_set = true;
       break;
@@ -992,13 +2042,13 @@ common_handle_option (size_t scode, const char *arg, int value,
       flag_pedantic_errors = pedantic = 1;
       break;
 
-    case OPT_fforce_mem:
-      warning (0, "-f[no-]force-mem is nop and option will be removed in 4.2");
-      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:
+    case OPT_ftree_store_ccp:
       /* These are no-ops, preserved for backward compatibility.  */
       break;
 
@@ -1043,8 +2093,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
      -Wuninitialized on the command line, we need to generate a
@@ -1055,21 +2103,20 @@ set_Wextra (int setting)
     warn_uninitialized = 2;
 }
 
-/* Initialize unused warning flags.  */
+/* 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_Wunused (int setting)
+set_Wstrict_aliasing (int onoff)
 {
-  warn_unused_function = setting;
-  warn_unused_label = setting;
-  /* Unused function parameter warnings are reported when either
-     ``-Wextra -Wunused'' or ``-Wunused-parameter'' is specified.
-     Thus, if -Wextra has already been seen, set warn_unused_parameter;
-     otherwise set maybe_warn_extra_parameter, which will be picked up
-     by set_Wextra.  */
-  maybe_warn_unused_parameter = setting;
-  warn_unused_parameter = (setting && extra_warnings);
-  warn_unused_variable = setting;
-  warn_unused_value = setting;
+  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
@@ -1077,8 +2124,8 @@ set_Wunused (int setting)
 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)
@@ -1089,6 +2136,17 @@ set_fast_math_flags (int set)
     }
 }
 
+/* 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)
@@ -1096,9 +2154,22 @@ fast_math_flags_set_p (void)
   return (!flag_trapping_math
          && flag_unsafe_math_optimizations
          && flag_finite_math_only
+         && !flag_signed_zeros
          && !flag_errno_math);
 }
 
+/* Return true iff flags are set as if -ffast-math but using the flags stored
+   in the struct cl_optimization structure.  */
+bool
+fast_math_flags_struct_set_p (struct cl_optimization *opt)
+{
+  return (!opt->flag_trapping_math
+         && opt->flag_unsafe_math_optimizations
+         && opt->flag_finite_math_only
+         && !opt->flag_signed_zeros
+         && !opt->flag_errno_math);
+}
+
 /* Handle a debug output -g switch.  EXTENDED is true or false to support
    extended output (2 is special and means "-ggdb" was given).  */
 static void
@@ -1153,238 +2224,6 @@ set_debug_level (enum debug_info_type type, int extended, const char *arg)
     }
 }
 
-/* Display help for target options.  */
-static void
-print_target_help (void)
-{
-  unsigned int i;
-  static bool displayed = false;
-
-  /* Avoid double printing for --help --target-help.  */
-  if (displayed)
-    return;
-
-  displayed = true;
-  for (i = 0; i < cl_options_count; i++)
-    if ((cl_options[i].flags & (CL_TARGET | CL_UNDOCUMENTED)) == CL_TARGET)
-      {
-       printf (_("\nTarget specific options:\n"));
-       print_filtered_help (CL_TARGET);
-       break;
-      }
-}
-
-/* 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);
-    }
-  print_target_help ();
-}
-
-/* Print the help for --param.  */
-static void
-print_param_help (void)
-{
-  size_t i;
-
-  puts (_("The --param option recognizes the following as parameters:\n"));
-
-  for (i = 0; i < LAST_PARAM; i++)
-    {
-      const char *help = compiler_params[i].help;
-      const char *param = compiler_params[i].option;
-
-      if (help == NULL || *help == '\0')
-       help = undocumented_msg;
-
-      /* Get the translation.  */
-      help = _(help);
-
-      wrap_help (help, param, strlen (param));
-    }
-
-  putchar ('\n');
-}
-
-/* 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 || flag == CL_TARGET)
-    {
-      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);
-           }
-       }
-
-      if (duplicates)
-       {
-         putchar ('\n');
-         putchar ('\n');
-       }
-    }
-
-  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.  */
-      if (printed[i])
-       continue;
-
-      printed[i] = true;
-
-      help = cl_options[i].help;
-      if (!help)
-       help = undocumented_msg;
-
-      /* Get the translation.  */
-      help = _(help);
-
-      tab = strchr (help, '\t');
-      if (tab)
-       {
-         len = tab - help;
-         opt = help;
-         help = tab + 1;
-       }
-      else
-       {
-         opt = cl_options[i].opt_text;
-         len = strlen (opt);
-       }
-
-      wrap_help (help, opt, len);
-    }
-
-  putchar ('\n');
-}
-
-/* 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 */
-
-  if (indent)
-    {
-      putchar (',');
-      if (indent + len > columns)
-       {
-         putchar ('\n');
-         putchar (' ');
-         indent = 1;
-       }
-    }
-  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;
-    }
-  while (remaining);
-}
-
 /* Return 1 if OPTION is enabled, 0 if it is disabled, or -1 if it isn't
    a simple on-off switch.  */
 
@@ -1392,6 +2231,7 @@ int
 option_enabled (int opt_idx)
 {
   const struct cl_option *option = &(cl_options[opt_idx]);
+
   if (option->flag_var)
     switch (option->var_type)
       {
@@ -1441,8 +2281,39 @@ get_option_state (int option, struct cl_option_state *state)
       state->data = *(const char **) cl_options[option].flag_var;
       if (state->data == 0)
        state->data = "";
-      state->size = strlen (state->data) + 1;
+      state->size = strlen ((const char *) state->data) + 1;
       break;
     }
   return true;
 }
+
+/* Enable a warning option as an error.  This is used by -Werror= and
+   also by legacy Werror-implicit-function-declaration.  */
+
+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)
+    {
+      error ("-Werror=%s: No option -%s", arg, new_option);
+    }
+  else
+    {
+      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;
+    }
+  free (new_option);
+}