OSDN Git Service

(notice_cc_update): Set CC_FCOMI is this is a float compare.
[pf3gnuchains/gcc-fork.git] / gcc / toplev.c
index a05ebd5..855aaca 100644 (file)
@@ -1,5 +1,5 @@
 /* Top level of GNU C compiler
-   Copyright (C) 1987, 88, 89, 92-5, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 92-6, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -62,6 +62,7 @@ Boston, MA 02111-1307, USA.  */
 #include "output.h"
 #include "bytecode.h"
 #include "bc-emit.h"
+#include "except.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"
@@ -92,6 +93,39 @@ vms_fopen (fname, type)
 #define DEFAULT_GDB_EXTENSIONS 1
 #endif
 
+/* If more than one debugging type is supported, you must define
+   PREFERRED_DEBUGGING_TYPE to choose a format in a system-dependent way. 
+
+   This is one long line cause VAXC can't handle a \-newline.  */
+#if 1 < (defined (DBX_DEBUGGING_INFO) + defined (SDB_DEBUGGING_INFO) + defined (DWARF_DEBUGGING_INFO) + defined (DWARF2_DEBUGGING_INFO) + defined (XCOFF_DEBUGGING_INFO))
+#ifndef PREFERRED_DEBUGGING_TYPE
+You Lose!  You must define PREFERRED_DEBUGGING_TYPE!
+#endif /* no PREFERRED_DEBUGGING_TYPE */
+#else /* Only one debugging format supported.  Define PREFERRED_DEBUGGING_TYPE
+        so the following code needn't care.  */
+#ifdef DBX_DEBUGGING_INFO
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+#endif
+#ifdef SDB_DEBUGGING_INFO
+#define PREFERRED_DEBUGGING_TYPE SDB_DEBUG
+#endif
+#ifdef DWARF_DEBUGGING_INFO
+#define PREFERRED_DEBUGGING_TYPE DWARF_DEBUG
+#endif
+#ifdef DWARF2_DEBUGGING_INFO
+#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
+#endif
+#ifdef XCOFF_DEBUGGING_INFO
+#define PREFERRED_DEBUGGING_TYPE XCOFF_DEBUG
+#endif
+#endif /* More than one debugger format enabled.  */
+
+/* If still not defined, must have been because no debugging formats
+   are supported.  */
+#ifndef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE NO_DEBUG
+#endif
+
 extern int rtx_equal_function_value_matters;
 
 #if ! (defined (VMS) || defined (OS2))
@@ -206,6 +240,7 @@ int jump_opt_dump = 0;
 int cse_dump = 0;
 int loop_dump = 0;
 int cse2_dump = 0;
+int branch_prob_dump = 0;
 int flow_dump = 0;
 int combine_dump = 0;
 int sched_dump = 0;
@@ -258,9 +293,15 @@ int sorrycount = 0;
 /* Flag to output bytecode instead of native assembler */
 int output_bytecode = 0;
 
-/* Pointer to function to compute the name to use to print a declaration.  */
+/* Pointer to function to compute the name to use to print a declaration.
+   DECL is the declaration in question.
+   VERBOSITY determines what information will be printed:
+     0: DECL_NAME, demangled as necessary.
+     1: and scope information.
+     2: and any other information that might be interesting, such as function
+        parameter types in C++.  */
 
-char *(*decl_printable_name) ();
+char *(*decl_printable_name) (/* tree decl, int verbosity */);
 
 /* Pointer to function to compute rtl for a language-specific tree code.  */
 
@@ -271,12 +312,6 @@ struct rtx_def *(*lang_expand_expr) ();
 
 void (*incomplete_decl_finalize_hook) () = 0;
 
-/* Pointer to function for interim exception handling implementation.
-   This interface will change, and it is only here until a better interface
-   replaces it.  */
-
-void (*interim_eh_hook)        PROTO((tree));
-
 /* Highest label number used at the end of reload.  */
 
 int max_label_num_after_reload;
@@ -289,6 +324,18 @@ int profile_flag = 0;
 
 int profile_block_flag;
 
+/* Nonzero if generating code to profile program flow graph arcs.  */
+
+int profile_arc_flag = 0;
+
+/* Nonzero if generating info for gcov to calculate line test coverage.  */
+
+int flag_test_coverage = 0;
+
+/* Nonzero indicates that branch taken probabilities should be calculated.  */
+
+int flag_branch_probabilities = 0;
+
 /* Nonzero for -pedantic switch: warn about anything
    that standard spec forbids.  */
 
@@ -481,10 +528,6 @@ int flag_shared_data;
 
 int flag_delayed_branch;
 
-/* Nonzero means to run cleanups after CALL_EXPRs.  */
-
-int flag_short_temps;
-
 /* Nonzero if we are compiling pure (sharable) code.
    Value is 1 if we are doing reasonable (i.e. simple
    offset into offset table) pic.  Value is 2 if we can
@@ -492,8 +535,13 @@ int flag_short_temps;
 
 int flag_pic;
 
+/* Nonzero means generate extra code for exception handling and enable
+   exception handling.  */
+
+int flag_exceptions = 1;
+
 /* Nonzero means don't place uninitialized global data in common storage
-   by default. */
+   by default.  */
 
 int flag_no_common;
 
@@ -593,6 +641,12 @@ struct { char *string; int *variable; int on_value;} f_options[] =
   {"schedule-insns2", &flag_schedule_insns_after_reload, 1},
   {"pic", &flag_pic, 1},
   {"PIC", &flag_pic, 2},
+  {"exceptions", &flag_exceptions, 1},
+  {"sjlj-exceptions", &exceptions_via_longjmp, 1},
+  {"asynchronous-exceptions", &asynchronous_exceptions, 1},
+  {"profile-arcs", &profile_arc_flag, 1},
+  {"test-coverage", &flag_test_coverage, 1},
+  {"branch-probabilities", &flag_branch_probabilities, 1},
   {"fast-math", &flag_fast_math, 1},
   {"common", &flag_no_common, 0},
   {"inhibit-size-directive", &flag_inhibit_size_directive, 1},
@@ -628,6 +682,10 @@ char *lang_options[] =
   "-fno-asm",
   "-fbuiltin",
   "-fno-builtin",
+  "-fhosted",
+  "-fno-hosted",
+  "-ffreestanding",
+  "-fno-freestanding",
   "-fcond-mismatch",
   "-fno-cond-mismatch",
   "-fdollars-in-identifiers",
@@ -658,6 +716,8 @@ char *lang_options[] =
   "-Wno-import",
   "-Wimplicit",
   "-Wno-implicit",
+  "-Wmain",
+  "-Wno-main",
   "-Wmissing-braces",
   "-Wno-missing-braces",
   "-Wmissing-declarations",
@@ -680,6 +740,8 @@ char *lang_options[] =
   "-Wno-traditional",
   "-Wtrigraphs",
   "-Wno-trigraphs",
+  "-Wundef",
+  "-Wno-undef",
   "-Wwrite-strings",
   "-Wno-write-strings",
 
@@ -786,6 +848,7 @@ FILE *jump_opt_dump_file;
 FILE *cse_dump_file;
 FILE *loop_dump_file;
 FILE *cse2_dump_file;
+FILE *branch_prob_dump_file;
 FILE *flow_dump_file;
 FILE *combine_dump_file;
 FILE *sched_dump_file;
@@ -805,6 +868,7 @@ int jump_time;
 int cse_time;
 int loop_time;
 int cse2_time;
+int branch_prob_time;
 int flow_time;
 int combine_time;
 int sched_time;
@@ -991,21 +1055,12 @@ fatal_insn_not_found (insn)
 /* This is the default decl_printable_name function.  */
 
 static char *
-decl_name (decl, kind)
+decl_name (decl, verbosity)
      tree decl;
-     char **kind;
+     int verbosity;
 {
   return IDENTIFIER_POINTER (DECL_NAME (decl));
 }
-
-/* This is the default interim_eh_hook function.  */
-
-void
-interim_eh (finalization)
-     tree finalization;
-{
-  /* Don't do anything by default.  */
-}
 \f
 static int need_error_newline;
 
@@ -1026,11 +1081,10 @@ announce_function (decl)
 {
   if (! quiet_flag)
     {
-      char *junk;
       if (rtl_dump_and_exit)
        fprintf (stderr, "%s ", IDENTIFIER_POINTER (DECL_NAME (decl)));
       else
-       fprintf (stderr, " %s", (*decl_printable_name) (decl, &junk));
+       fprintf (stderr, " %s", (*decl_printable_name) (decl, 2));
       fflush (stderr);
       need_error_newline = 1;
       last_error_function = current_function_decl;
@@ -1058,7 +1112,7 @@ default_print_error_function (file)
        fprintf (stderr, "At top level:\n");
       else
        {
-         char *name = (*decl_printable_name) (current_function_decl, &kind);
+         char *name = (*decl_printable_name) (current_function_decl, 2);
          fprintf (stderr, "In %s `%s':\n", kind, name);
        }
 
@@ -1156,7 +1210,7 @@ v_message_with_decl (decl, prefix, s, ap)
      char *s;
      va_list ap;
 {
-  char *n, *p, *junk;
+  char *n, *p;
 
   fprintf (stderr, "%s:%d: ",
           DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl));
@@ -1192,7 +1246,7 @@ v_message_with_decl (decl, prefix, s, ap)
   if (*p == '%')               /* Print the name.  */
     {
       char *n = (DECL_NAME (decl)
-                ? (*decl_printable_name) (decl, &junk)
+                ? (*decl_printable_name) (decl, 2)
                 : "((anonymous))");
       fputs (n, stderr);
       while (*p)
@@ -1839,9 +1893,27 @@ floor_log2_wide (x)
   return log;
 }
 
+static int float_handler_set;
 int float_handled;
 jmp_buf float_handler;
 
+/* Signals actually come here.  */
+
+static void
+float_signal (signo)
+     /* If this is missing, some compilers complain.  */
+     int signo;
+{
+  if (float_handled == 0)
+    abort ();
+#if defined (USG) || defined (hpux)
+  signal (SIGFPE, float_signal);  /* re-enable the signal catcher */
+#endif
+  float_handled = 0;
+  signal (SIGFPE, float_signal);
+  longjmp (float_handler, 1);
+}
+
 /* Specify where to longjmp to when a floating arithmetic error happens.
    If HANDLER is 0, it means don't handle the errors any more.  */
 
@@ -1852,6 +1924,12 @@ set_float_handler (handler)
   float_handled = (handler != 0);
   if (handler)
     bcopy ((char *) handler, (char *) float_handler, sizeof (float_handler));
+
+  if (float_handled && ! float_handler_set)
+    {
+      signal (SIGFPE, float_signal);
+      float_handler_set = 1;
+    }
 }
 
 /* Specify, in HANDLER, where to longjmp to when a floating arithmetic
@@ -1886,23 +1964,6 @@ pop_float_handler (handled, handler)
     bcopy ((char *) handler, (char *) float_handler, sizeof (float_handler));
 }
 
-/* Signals actually come here.  */
-
-static void
-float_signal (signo)
-     /* If this is missing, some compilers complain.  */
-     int signo;
-{
-  if (float_handled == 0)
-    abort ();
-#if defined (USG) || defined (hpux)
-  signal (SIGFPE, float_signal);  /* re-enable the signal catcher */
-#endif
-  float_handled = 0;
-  signal (SIGFPE, float_signal);
-  longjmp (float_handler, 1);
-}
-
 /* Handler for SIGPIPE.  */
 
 static void
@@ -2033,6 +2094,7 @@ compile_file (name)
   cse_time = 0;
   loop_time = 0;
   cse2_time = 0;
+  branch_prob_time = 0;
   flow_time = 0;
   combine_time = 0;
   sched_time = 0;
@@ -2071,7 +2133,8 @@ compile_file (name)
      but the options would have to be parsed first to know that. -bson */
   init_rtl ();
   init_emit_once (debug_info_level == DINFO_LEVEL_NORMAL
-                 || debug_info_level == DINFO_LEVEL_VERBOSE);
+                 || debug_info_level == DINFO_LEVEL_VERBOSE
+                 || flag_test_coverage);
   init_regs ();
   init_decl_processing ();
   init_optabs ();
@@ -2114,6 +2177,10 @@ compile_file (name)
   if (cse2_dump)
     cse2_dump_file = open_dump_file (dump_base_name, ".cse2");
 
+  /* If branch_prob dump desired, open the output file.  */
+  if (branch_prob_dump)
+    branch_prob_dump_file = open_dump_file (dump_base_name, ".bp");
+
   /* If flow dump desired, open the output file.  */
   if (flow_dump)
     flow_dump_file = open_dump_file (dump_base_name, ".flow");
@@ -2293,11 +2360,16 @@ compile_file (name)
   if (write_symbols == DWARF_DEBUG)
     TIMEVAR (symout_time, dwarfout_init (asm_out_file, main_input_filename));
 #endif
+#ifdef DWARF2_DEBUGGING_INFO
+  if (write_symbols == DWARF2_DEBUG)
+    TIMEVAR (symout_time, dwarf2out_init (asm_out_file, main_input_filename));
+#endif
 
   /* Initialize yet another pass.  */
 
   if (!output_bytecode)
     init_final (main_input_filename);
+  init_branch_prob (dump_base_name);
 
   start_time = get_run_time ();
 
@@ -2315,6 +2387,8 @@ compile_file (name)
        poplevel (0, 0, 0);
     }
 
+  output_func_start_profiler ();
+
   /* Compilation is now finished except for writing
      what's left of the symbol table output.  */
 
@@ -2416,6 +2490,12 @@ compile_file (name)
          }
       }
 
+    /* Now that all possible functions have been output, we can dump
+       the exception table.  */
+
+    if (exception_table_p ())
+      output_exception_table ();
+
     for (i = 0; i < len; i++)
       {
        decl = vec[i];
@@ -2495,6 +2575,16 @@ compile_file (name)
            && (TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl)))
          TIMEVAR (symout_time, dwarfout_file_scope_decl (decl, 1));
 #endif
+#ifdef DWARF2_DEBUGGING_INFO
+       /* Output DWARF2 information for file-scope tentative data object
+          declarations, file-scope (extern) function declarations (which
+          had no corresponding body) and file-scope tagged type declarations
+          and definitions which have not yet been forced out.  */
+
+       if (write_symbols == DWARF2_DEBUG
+           && (TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl)))
+         TIMEVAR (symout_time, dwarf2out_decl (decl));
+#endif
       }
   }
 
@@ -2519,11 +2609,20 @@ compile_file (name)
             });
 #endif
 
+#ifdef DWARF2_DEBUGGING_INFO
+  if (write_symbols == DWARF2_DEBUG)
+    TIMEVAR (symout_time,
+            {
+              dwarf2out_finish ();
+            });
+#endif
+
   /* Output some stuff at end of file if nec.  */
 
   if (!output_bytecode)
     {
-      end_final (main_input_filename);
+      end_final (dump_base_name);
+      end_branch_prob (branch_prob_dump_file);
 
 #ifdef ASM_FILE_END
       ASM_FILE_END (asm_out_file);
@@ -2561,6 +2660,9 @@ compile_file (name)
   if (cse2_dump)
     fclose (cse2_dump_file);
 
+  if (branch_prob_dump)
+    fclose (branch_prob_dump_file);
+
   if (flow_dump)
     fclose (flow_dump_file);
 
@@ -2615,6 +2717,7 @@ compile_file (name)
          print_time ("cse", cse_time);
          print_time ("loop", loop_time);
          print_time ("cse2", cse2_time);
+         print_time ("branch-prob", branch_prob_time);
          print_time ("flow", flow_time);
          print_time ("combine", combine_time);
          print_time ("sched", sched_time);
@@ -2830,6 +2933,17 @@ rest_of_compilation (decl)
                  set_decl_abstract_flags (decl, 0);
                }
 #endif
+#ifdef DWARF2_DEBUGGING_INFO
+             /* Generate the DWARF2 info for the "abstract" instance
+                of a function which we may later generate inlined and/or
+                out-of-line instances of.  */
+             if (write_symbols == DWARF2_DEBUG)
+               {
+                 set_decl_abstract_flags (decl, 1);
+                 TIMEVAR (symout_time, dwarf2out_decl (decl));
+                 set_decl_abstract_flags (decl, 0);
+               }
+#endif
              TIMEVAR (integration_time, save_for_inline_nocopy (decl));
              RTX_INTEGRATED_P (DECL_SAVED_INSNS (decl)) = inlineable;
              goto exit_rest_of_compilation;
@@ -2852,6 +2966,18 @@ rest_of_compilation (decl)
              set_decl_abstract_flags (decl, 0);
            }
 #endif
+#ifdef DWARF2_DEBUGGING_INFO
+         /* Generate the DWARF2 info for the "abstract" instance of
+            a function which we will generate an out-of-line instance
+            of almost immediately (and which we may also later generate
+            various inlined instances of).  */
+         if (write_symbols == DWARF2_DEBUG)
+           {
+             set_decl_abstract_flags (decl, 1);
+             TIMEVAR (symout_time, dwarf2out_decl (decl));
+             set_decl_abstract_flags (decl, 0);
+           }
+#endif
          saved_block_tree = DECL_INITIAL (decl);
          saved_arguments = DECL_ARGUMENTS (decl);
          TIMEVAR (integration_time, save_for_inline_copying (decl));
@@ -2878,12 +3004,9 @@ rest_of_compilation (decl)
       goto exit_rest_of_compilation;
     }
 
-  /* From now on, allocate rtl in current_obstack, not in saveable_obstack.
-     Note that that may have been done above, in save_for_inline_copying.
-     The call to resume_temporary_allocation near the end of this function
-     goes back to the usual state of affairs.  */
-
-  rtl_in_current_obstack ();
+  /* Add an unwinder for exception handling, if needed.
+     This must be done before we finalize PIC code.  */
+  emit_unwinder ();
 
 #ifdef FINALIZE_PIC
   /* If we are doing position-independent code generation, now
@@ -2894,6 +3017,15 @@ rest_of_compilation (decl)
     FINALIZE_PIC;
 #endif
 
+  /* From now on, allocate rtl in current_obstack, not in saveable_obstack.
+     Note that that may have been done above, in save_for_inline_copying.
+     The call to resume_temporary_allocation near the end of this function
+     goes back to the usual state of affairs.  This must be done after
+     we've built up any unwinders for exception handling, and done
+     the FINALIZE_PIC work, if necessary.  */
+
+  rtl_in_current_obstack ();
+
   insns = get_insns ();
 
   /* Copy any shared structure that should not be shared.  */
@@ -2909,6 +3041,9 @@ rest_of_compilation (decl)
      for all references to such slots.  */
 /*   fixup_stack_slots (); */
 
+  /* Find all the EH handlers.  */
+  find_exception_handler_labels ();
+
   /* Always do one jump optimization pass to ensure that JUMP_LABEL fields
      are initialized and to compute whether control can drop off the end
      of the function.  */
@@ -3018,10 +3153,12 @@ rest_of_compilation (decl)
     }
 
   if (optimize > 0 && flag_thread_jumps)
-    /* This pass of jump threading straightens out code
-       that was kinked by loop optimization.  */
-    TIMEVAR (jump_time, thread_jumps (insns, max_reg_num (), 0));
-
+    {
+      /* This pass of jump threading straightens out code
+         that was kinked by loop optimization.  */
+      TIMEVAR (jump_time, reg_scan (insns, max_reg_num (), 0));
+      TIMEVAR (jump_time, thread_jumps (insns, max_reg_num (), 0));
+    }
   /* Dump rtl code after cse, if we are doing that.  */
 
   if (cse2_dump)
@@ -3031,6 +3168,25 @@ rest_of_compilation (decl)
               fflush (cse2_dump_file);
             });
 
+  if (branch_prob_dump)
+    TIMEVAR (dump_time,
+            {
+              fprintf (branch_prob_dump_file, "\n;; Function %s\n\n",
+                       IDENTIFIER_POINTER (DECL_NAME (decl)));
+            });
+
+  if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
+    TIMEVAR (branch_prob_time,
+            {
+              branch_prob (insns, branch_prob_dump_file);
+            });
+
+  if (branch_prob_dump)
+    TIMEVAR (dump_time,
+            {
+              print_rtl (branch_prob_dump_file, insns);
+              fflush (branch_prob_dump_file);
+            });
   /* We are no longer anticipating cse in this function, at least.  */
 
   cse_not_expected = 1;
@@ -3337,6 +3493,11 @@ rest_of_compilation (decl)
     TIMEVAR (symout_time, dwarfout_file_scope_decl (decl, 0));
 #endif
 
+#ifdef DWARF2_DEBUGGING_INFO
+  if (write_symbols == DWARF2_DEBUG)
+    TIMEVAR (symout_time, dwarf2out_decl (decl));
+#endif
+
  exit_rest_of_compilation:
 
   /* In case the function was not output,
@@ -3353,9 +3514,11 @@ rest_of_compilation (decl)
      the copy, but the original is unchanged.  */
 
   if (saved_block_tree != 0)
-    DECL_INITIAL (decl) = saved_block_tree;
-  if (saved_arguments != 0)
-    DECL_ARGUMENTS (decl) = saved_arguments;
+    {
+      DECL_INITIAL (decl) = saved_block_tree;
+      DECL_ARGUMENTS (decl) = saved_arguments;
+      DECL_ABSTRACT_ORIGIN (decl) = NULL_TREE;
+    }
 
   reload_completed = 0;
 
@@ -3430,7 +3593,6 @@ main (argc, argv, envp)
 
   decl_printable_name = decl_name;
   lang_expand_expr = (struct rtx_def *(*)()) do_abort;
-  interim_eh_hook = interim_eh;
 
   /* Initialize whether `char' is signed.  */
   flag_signed_char = DEFAULT_SIGNED_CHAR;
@@ -3462,11 +3624,6 @@ main (argc, argv, envp)
     }
 
   obey_regdecls = (optimize == 0);
-  if (optimize == 0)
-    {
-      flag_no_inline = 1;
-      warn_inline = 0;
-    }
 
   if (optimize >= 1)
     {
@@ -3545,6 +3702,7 @@ main (argc, argv, envp)
                switch (*p++)
                  {
                  case 'a':
+                   branch_prob_dump = 1;
                    combine_dump = 1;
                    dbr_sched_dump = 1;
                    flow_dump = 1;
@@ -3559,6 +3717,9 @@ main (argc, argv, envp)
                    sched2_dump = 1;
                    stack_reg_dump = 1;
                    break;
+                 case 'b':
+                   branch_prob_dump = 1;
+                   break;
                  case 'k':
                    stack_reg_dump = 1;
                    break;
@@ -3778,133 +3939,121 @@ main (argc, argv, envp)
            }
          else if (str[0] == 'g')
            {
-             char *p = str + 1;
-             char *q;
              unsigned len;
              unsigned level;
-
-             while (*p && (*p < '0' || *p > '9'))
-               p++;
-             len = p - str;
-             q = p;
-             while (*q && (*q >= '0' && *q <= '9'))
-               q++;
-             if (*p)
-               level = atoi (p);
-             else
-               level = 2;      /* default debugging info level */
-             if (*q || level > 3)
-               {
-                 warning ("invalid debug level specification in option: `-%s'",
-                          str);
-                 warning ("no debugging information will be generated");
-                 level = 0;
-               }
-
-             /* If more than one debugging type is supported,
-                you must define PREFERRED_DEBUGGING_TYPE
-                to choose a format in a system-dependent way.  */
-             /* This is one long line cause VAXC can't handle a \-newline.  */
-#if 1 < (defined (DBX_DEBUGGING_INFO) + defined (SDB_DEBUGGING_INFO) + defined (DWARF_DEBUGGING_INFO) + defined (XCOFF_DEBUGGING_INFO))
-#ifdef PREFERRED_DEBUGGING_TYPE
-             if (!strncmp (str, "ggdb", len))
-               write_symbols = PREFERRED_DEBUGGING_TYPE;
-#else /* no PREFERRED_DEBUGGING_TYPE */
-You Lose!  You must define PREFERRED_DEBUGGING_TYPE!
-#endif /* no PREFERRED_DEBUGGING_TYPE */
-#endif /* More than one debugger format enabled.  */
+             /* A lot of code assumes write_symbols == NO_DEBUG if the
+                debugging level is 0 (thus -gstabs1 -gstabs0 would lose track
+                of what debugging type has been selected).  This records the
+                selected type.  It is an error to specify more than one
+                debugging type.  */
+             static enum debug_info_type selected_debug_type = NO_DEBUG;
+             /* Non-zero if debugging format has been explicitly set.
+                -g and -ggdb don't explicitly set the debugging format so
+                -gdwarf -g3 is equivalent to -gdwarf3.  */
+             static int type_explicitly_set_p = 0;
+             /* Table of supported debugging formats.  */
+             static struct {
+               char *arg;
+               /* Since PREFERRED_DEBUGGING_TYPE isn't necessarily a
+                  constant expression, we use NO_DEBUG in its place.  */
+               enum debug_info_type debug_type;
+               int use_extensions_p;
+             } *da, debug_args[] = {
+               { "g", NO_DEBUG, DEFAULT_GDB_EXTENSIONS },
+               { "ggdb", NO_DEBUG, 1 },
 #ifdef DBX_DEBUGGING_INFO
-             if (write_symbols != NO_DEBUG)
-               ;
-             else if (!strncmp (str, "ggdb", len))
-               write_symbols = DBX_DEBUG;
-             else if (!strncmp (str, "gstabs", len))
-               write_symbols = DBX_DEBUG;
-             else if (!strncmp (str, "gstabs+", len))
-               write_symbols = DBX_DEBUG;
-
-             /* Always enable extensions for -ggdb or -gstabs+, 
-                always disable for -gstabs.
-                For plain -g, use system-specific default.  */
-             if (write_symbols == DBX_DEBUG && !strncmp (str, "ggdb", len)
-                 && len >= 2)
-               use_gnu_debug_info_extensions = 1;
-             else if (write_symbols == DBX_DEBUG && !strncmp (str, "gstabs+", len)
-                      && len >= 7)
-               use_gnu_debug_info_extensions = 1;
-             else if (write_symbols == DBX_DEBUG
-                      && !strncmp (str, "gstabs", len) && len >= 2)
-               use_gnu_debug_info_extensions = 0;
-             else
-               use_gnu_debug_info_extensions = DEFAULT_GDB_EXTENSIONS;
-#endif /* DBX_DEBUGGING_INFO */
+               { "gstabs", DBX_DEBUG, 0 },
+               { "gstabs+", DBX_DEBUG, 1 },
+#endif
 #ifdef DWARF_DEBUGGING_INFO
-             if (write_symbols != NO_DEBUG)
-               ;
-             else if (!strncmp (str, "g", len))
-               write_symbols = DWARF_DEBUG;
-             else if (!strncmp (str, "ggdb", len))
-               write_symbols = DWARF_DEBUG;
-             else if (!strncmp (str, "gdwarf", len))
-               write_symbols = DWARF_DEBUG;
-
-             /* Always enable extensions for -ggdb or -gdwarf+, 
-                always disable for -gdwarf.
-                For plain -g, use system-specific default.  */
-             if (write_symbols == DWARF_DEBUG && !strncmp (str, "ggdb", len)
-                 && len >= 2)
-               use_gnu_debug_info_extensions = 1;
-             else if (write_symbols == DWARF_DEBUG && !strcmp (str, "gdwarf+"))
-               use_gnu_debug_info_extensions = 1;
-             else if (write_symbols == DWARF_DEBUG
-                      && !strncmp (str, "gdwarf", len) && len >= 2)
-               use_gnu_debug_info_extensions = 0;
-             else
-               use_gnu_debug_info_extensions = DEFAULT_GDB_EXTENSIONS;
+               { "gdwarf", DWARF_DEBUG, 0 },
+               { "gdwarf+", DWARF_DEBUG, 1 },
+#endif
+#ifdef DWARF2_DEBUGGING_INFO
+               { "gdwarf-2", DWARF2_DEBUG, 0 },
 #endif
-#ifdef SDB_DEBUGGING_INFO
-             if (write_symbols != NO_DEBUG)
-               ;
-             else if (!strncmp (str, "g", len))
-               write_symbols = SDB_DEBUG;
-             else if (!strncmp (str, "gdb", len))
-               write_symbols = SDB_DEBUG;
-             else if (!strncmp (str, "gcoff", len))
-               write_symbols = SDB_DEBUG;
-#endif /* SDB_DEBUGGING_INFO */
 #ifdef XCOFF_DEBUGGING_INFO
-             if (write_symbols != NO_DEBUG)
-               ;
-             else if (!strncmp (str, "g", len))
-               write_symbols = XCOFF_DEBUG;
-             else if (!strncmp (str, "ggdb", len))
-               write_symbols = XCOFF_DEBUG;
-             else if (!strncmp (str, "gxcoff", len))
-               write_symbols = XCOFF_DEBUG;
-             else if (!strncmp (str, "gxcoff+", len))
-               write_symbols = XCOFF_DEBUG;
-
-             /* Always enable extensions for -ggdb or -gxcoff+,
-                always disable for -gxcoff.
-                For plain -g, use system-specific default.  */
-             if (write_symbols == XCOFF_DEBUG && !strncmp (str, "ggdb", len)
-                 && len >= 2)
-               use_gnu_debug_info_extensions = 1;
-             else if (write_symbols == XCOFF_DEBUG && !strcmp (str, "gxcoff+"))
-               use_gnu_debug_info_extensions = 1;
-             else if (write_symbols == XCOFF_DEBUG
-                      && !strncmp (str, "gxcoff", len) && len >= 2)
-               use_gnu_debug_info_extensions = 0;
-             else
-               use_gnu_debug_info_extensions = DEFAULT_GDB_EXTENSIONS;
-#endif       
-             if (write_symbols == NO_DEBUG)
+               { "gxcoff", XCOFF_DEBUG, 0 },
+               { "gxcoff+", XCOFF_DEBUG, 1 },
+#endif
+#ifdef SDB_DEBUGGING_INFO
+               { "gcoff", SDB_DEBUG, 0 },
+#endif
+               { 0, 0, 0 }
+             };
+             /* Indexed by enum debug_info_type.  */
+             static char *debug_type_names[] = {
+               "none", "stabs", "coff", "dwarf-1", "dwarf-2", "xcoff"
+             };
+
+             /* Look up STR in the table.  */
+             for (da = debug_args; da->arg; da++)
+               {
+                 if (! strncmp (str, da->arg, strlen (da->arg)))
+                   {
+                     enum debug_info_type type = da->debug_type;
+                     char *p, *q;
+
+                     p = str + strlen (da->arg);
+                     if (*p && (*p < '0' || *p > '9'))
+                       continue;
+                     q = p;
+                     while (*q && (*q >= '0' && *q <= '9'))
+                       q++;
+                     if (*p)
+                       level = atoi (p);
+                     else
+                       level = 2;      /* default debugging info level */
+                     if (*q || level > 3)
+                       {
+                         warning ("invalid debug level specification in option: `-%s'",
+                                  str);
+                         /* ??? This error message is incorrect in the case of
+                            -g4 -g.  */
+                         warning ("no debugging information will be generated");
+                         level = 0;
+                       }
+
+                     /* ??? A few targets use STR in the
+                        definition of PREFERRED_DEBUGGING_TYPE!  */
+                     if (type == NO_DEBUG)
+                       type = PREFERRED_DEBUGGING_TYPE;
+
+                     if (type == NO_DEBUG)
+                       warning ("`-%s' not supported by this configuration of GCC",
+                                str);
+
+                     /* Does it conflict with an already selected type?  */
+                     if (type_explicitly_set_p
+                         /* -g/-ggdb don't conflict with anything */
+                         && da->debug_type != NO_DEBUG
+                         && type != selected_debug_type)
+                       warning ("`-%s' ignored, conflicts with `-g%s'",
+                                str, debug_type_names[(int) selected_debug_type]);
+                     else
+                       {
+                         /* If the format has already been set, -g/-ggdb
+                            only change the debug level.  */
+                         if (type_explicitly_set_p
+                             && da->debug_type == NO_DEBUG)
+                           ; /* don't change debugging type */
+                         else
+                           {
+                             selected_debug_type = type;
+                             type_explicitly_set_p = da->debug_type != NO_DEBUG;
+                           }
+                         write_symbols = (level == 0
+                                          ? NO_DEBUG
+                                          : selected_debug_type);
+                         use_gnu_debug_info_extensions = da->use_extensions_p;
+                         debug_info_level = (enum debug_info_level) level;
+                       }
+                     break;
+                   }
+               }
+             if (! da->arg)
                warning ("`-%s' not supported by this configuration of GCC",
                         str);
-             else if (level == 0)
-               write_symbols = NO_DEBUG;
-             else
-               debug_info_level = (enum debug_info_level) level;
            }
          else if (!strcmp (str, "o"))
            {
@@ -3935,7 +4084,7 @@ You Lose!  You must define PREFERRED_DEBUGGING_TYPE!
     {
 #ifndef TARGET_SUPPORTS_BYTECODE
       /* Just die with a fatal error if not supported */
-      fatal ("-fbytecode not supporter for this target");
+      fatal ("-fbytecode not supported for this target");
 #else
       bc_initialize ();
 #endif
@@ -3955,15 +4104,6 @@ You Lose!  You must define PREFERRED_DEBUGGING_TYPE!
        warning ("-Wuninitialized is not supported without -O");
     }
 
-#if defined(DWARF_DEBUGGING_INFO)
-  if (write_symbols == DWARF_DEBUG
-      && strcmp (language_string, "GNU C++") == 0)
-    {
-      warning ("-g option not supported for C++ on systems using the DWARF debugging format");
-      write_symbols = NO_DEBUG;
-    }
-#endif /* defined(DWARF_DEBUGGING_INFO) */
-
 #ifdef OVERRIDE_OPTIONS
   /* Some machines may reject certain combinations of options.  */
   OVERRIDE_OPTIONS;
@@ -4010,7 +4150,7 @@ You Lose!  You must define PREFERRED_DEBUGGING_TYPE!
 
   compile_file (filename);
 
-#if !defined(OS2) && !defined(VMS) && !defined(_WIN32)
+#if !defined(OS2) && !defined(VMS) && (!defined(_WIN32) || defined (__CYGWIN32__))
   if (flag_print_mem)
     {
       char *lim = (char *) sbrk (0);
@@ -4025,7 +4165,7 @@ You Lose!  You must define PREFERRED_DEBUGGING_TYPE!
       system ("ps v");
 #endif /* not USG */
     }
-#endif /* not OS2 and not VMS and not _WIN32 */
+#endif /* ! OS2 && ! VMS && (! _WIN32 || CYGWIN32) */
 
   if (errorcount)
     exit (FATAL_EXIT_CODE);
@@ -4112,7 +4252,8 @@ print_version (file, indent)
 }
 
 /* Print an option value and return the adjusted position in the line.
-   ??? We don't handle error returns from fprintf (disk full).  */
+   ??? We don't handle error returns from fprintf (disk full); presumably
+   other code will catch a disk full though.  */
 
 int
 print_single_switch (file, pos, max, indent, sep, term, type, name)
@@ -4120,17 +4261,23 @@ print_single_switch (file, pos, max, indent, sep, term, type, name)
      int pos, max;
      char *indent, *sep, *term, *type, *name;
 {
+  /* The ultrix fprintf returns 0 on success, so compute the result we want
+     here since we need it for the following test.  */
+  int len = strlen (sep) + strlen (type) + strlen (name);
+
   if (pos != 0
-      && pos + strlen (sep) + strlen (type) + strlen (name) > max)
+      && pos + len > max)
     {
       fprintf (file, "%s", term);
       pos = 0;
     }
   if (pos == 0)
     {
-      pos = fprintf (file, "%s", indent);
+      fprintf (file, "%s", indent);
+      pos = strlen (indent);
     }
-  pos += fprintf (file, "%s%s%s", sep, type, name);
+  fprintf (file, "%s%s%s", sep, type, name);
+  pos += len;
   return pos;
 }
      
@@ -4214,3 +4361,98 @@ print_switch_values (file, pos, max, indent, sep, term)
 
   fprintf (file, "%s", term);
 }
+
+/* Record the beginning of a new source file, named FILENAME.  */
+
+void
+debug_start_source_file (filename)
+     register char *filename;
+{
+#ifdef DBX_DEBUGGING_INFO
+  if (write_symbols == DBX_DEBUG)
+    dbxout_start_new_source_file (filename);
+#endif
+#ifdef DWARF_DEBUGGING_INFO
+  if (debug_info_level == DINFO_LEVEL_VERBOSE
+      && write_symbols == DWARF_DEBUG)
+    dwarfout_start_new_source_file (filename);
+#endif /* DWARF_DEBUGGING_INFO */
+#ifdef DWARF2_DEBUGGING_INFO
+  if (debug_info_level == DINFO_LEVEL_VERBOSE
+      && write_symbols == DWARF2_DEBUG)
+    dwarf2out_start_source_file (filename);
+#endif /* DWARF2_DEBUGGING_INFO */  
+#ifdef SDB_DEBUGGING_INFO
+  if (write_symbols == SDB_DEBUG)
+    sdbout_start_new_source_file (filename);
+#endif
+}
+
+/* Record the resumption of a source file.  LINENO is the line number in
+   the source file we are returning to.  */
+
+void
+debug_end_source_file (lineno)
+     register unsigned lineno;
+{
+#ifdef DBX_DEBUGGING_INFO
+  if (write_symbols == DBX_DEBUG)
+    dbxout_resume_previous_source_file ();
+#endif
+#ifdef DWARF_DEBUGGING_INFO
+  if (debug_info_level == DINFO_LEVEL_VERBOSE
+      && write_symbols == DWARF_DEBUG)
+    dwarfout_resume_previous_source_file (lineno);
+#endif /* DWARF_DEBUGGING_INFO */
+#ifdef DWARF2_DEBUGGING_INFO
+  if (debug_info_level == DINFO_LEVEL_VERBOSE
+      && write_symbols == DWARF2_DEBUG)
+    dwarf2out_end_source_file ();
+#endif /* DWARF2_DEBUGGING_INFO */
+#ifdef SDB_DEBUGGING_INFO
+  if (write_symbols == SDB_DEBUG)
+    sdbout_resume_previous_source_file ();
+#endif
+}
+
+/* Called from check_newline in c-parse.y.  The `buffer' parameter contains
+   the tail part of the directive line, i.e. the part which is past the
+   initial whitespace, #, whitespace, directive-name, whitespace part.  */
+
+void
+debug_define (lineno, buffer)
+     register unsigned lineno;
+     register char *buffer;
+{
+#ifdef DWARF_DEBUGGING_INFO
+  if (debug_info_level == DINFO_LEVEL_VERBOSE
+      && write_symbols == DWARF_DEBUG)
+    dwarfout_define (lineno, buffer);
+#endif /* DWARF_DEBUGGING_INFO */
+#ifdef DWARF2_DEBUGGING_INFO
+  if (debug_info_level == DINFO_LEVEL_VERBOSE
+      && write_symbols == DWARF2_DEBUG)
+    dwarf2out_define (lineno, buffer);
+#endif /* DWARF2_DEBUGGING_INFO */
+}
+
+/* Called from check_newline in c-parse.y.  The `buffer' parameter contains
+   the tail part of the directive line, i.e. the part which is past the
+   initial whitespace, #, whitespace, directive-name, whitespace part.  */
+
+void
+debug_undef (lineno, buffer)
+     register unsigned lineno;
+     register char *buffer;
+{
+#ifdef DWARF_DEBUGGING_INFO
+  if (debug_info_level == DINFO_LEVEL_VERBOSE
+      && write_symbols == DWARF_DEBUG)
+    dwarfout_undef (lineno, buffer);
+#endif /* DWARF_DEBUGGING_INFO */
+#ifdef DWARF2_DEBUGGING_INFO
+  if (debug_info_level == DINFO_LEVEL_VERBOSE
+      && write_symbols == DWARF2_DEBUG)
+    dwarf2out_undef (lineno, buffer);
+#endif /* DWARF2_DEBUGGING_INFO */
+}