OSDN Git Service

boehm-gc:
[pf3gnuchains/gcc-fork.git] / gcc / opts.c
index ecbc9a3..78e746e 100644 (file)
@@ -77,6 +77,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 thet 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.  */
@@ -368,7 +618,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_baselength
+               = base_of_path (main_input_filename, &main_input_basename);
+           }
          add_input_filename (opt);
          n = 1;
          continue;
@@ -506,13 +760,21 @@ decode_options (unsigned int argc, const char **argv)
           /* 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;
+
+      /* Allow even more virtual operators.  */
+      set_param_value ("max-aliased-vops", 1000);
+      set_param_value ("avg-aliased-vops", 3);
     }
 
   if (optimize < 2 || optimize_size)
@@ -535,9 +797,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);
+      /* 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.  */
@@ -893,7 +1154,8 @@ print_specific_help (unsigned int include_flags,
              descrip_extra = lang_names [i];
            }
          else
-           description = _("The following options are supported by, amoung others, the language ");
+           description = _("The following options are supported by the language ");
+           descrip_extra = lang_names [i];
          break;
        }
     }
@@ -983,7 +1245,8 @@ common_handle_option (size_t scode, const char *arg, int value,
        /* Walk along the argument string, parsing each word in turn.
           The format is:
           arg = [^]{word}[,{arg}]
-          word = {optimizers|target|warnings|undocumented|params}  */
+          word = {optimizers|target|warnings|undocumented|
+                  params|common|<language>}  */
        while (* a != 0)
          {
            static struct
@@ -1000,6 +1263,7 @@ common_handle_option (size_t scode, const char *arg, int value,
              { "params", CL_PARAMS },
              { "joined", CL_JOINED },
              { "separate", CL_SEPARATE },
+             { "common", CL_COMMON },
              { NULL, 0 }
            };
            unsigned int * pflags;
@@ -1089,6 +1353,9 @@ common_handle_option (size_t scode, const char *arg, int value,
       break;
 
     case OPT_Wstrict_aliasing:
+      set_Wstrict_aliasing (value);
+      break;
+
     case OPT_Wstrict_aliasing_:
       warn_strict_aliasing = value;
       break;
@@ -1268,11 +1535,11 @@ 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_fsched_verbose_:
@@ -1452,6 +1719,20 @@ 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;
+}
+
 /* The following routines are useful in setting all the flags that
    -ffast-math and -fno-fast-math imply.  */
 void