This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[trunk<-vta] Re: [vta,vta4.3,trunk?] introduce -fcompare-debug


On Sep 11, 2008, Alexandre Oliva <aoliva@redhat.com> wrote:

> This patch introduces a better mechanism to test that the compiler
> produces the same output with and without -g than the one I've been
> using before.

> With this option, the compiler will compile the same program twice,
> dumping the final RTL and comparing the dumps.  This will enable us to
> verify that -g and/or -fvar-tracking-assignments have no codegen
> effects on our entire testsuite, and any other codebase you might want
> to compile with -fcompare-debug.

> This has already uncovered a number of codegen differences in a full
> build, that had been missed by bootstrap-debug and
> bootstrap-debug-lib.  I've already fixed some of them, but I still
> have others to fix.

> This also exposed a number of situations in which GCC compilers
> (rather than drivers) dumped information to stdout or to files not
> mentioned in the command line.  The patch below takes care of the ones
> I've located so far.

> One shortcoming of this approach is that it doesn't notice differences
> that aren't represented as RTL, such as data variable definitions and
> anything else that is not part of a function RTL.  I still haven't
> tried to add variables, initializers and constant pools, but this
> shouldn't be too hard, except that debug information output must be
> prevented from causing differences in the dumps.

> This could be useful for GCC even without VTA, to detect latent
> errors.  Probably too late for 4.4, but hey, it doesn't hurt to ask.
> Ok to install?

Ping?

Ok for trunk?

for  gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* common.opt (fcompare-debug=, fcompare-debug-second): New.
	(fdump-final-insns=): New.
	(gtoggle): New.
	* doc/invoke.texi: Document them.
	* final.c (rest_of_clean_state): Dump final insn stream.
	* gcc.c (invoke_as): Hook in -fcompare-debug.
	(static_spec_functions): Add compare-debug-dump-opt and
	compare-debug-self-opt.
	(compare_debug, compare_debug_second, compare_debug_opt): New.
	(switches_debug_check, n_switches_debug_check): New.
	(debug_check_temp_file): New.
	(process_command): Handle -fno-compare-debug, -fcompare-debug and
	-fcompare-debug=*.
	(do_self_spec): Handle arguments after switches.
	(do_spec_1): Add .gk extension to temp file basenames for compare.
	(check_live_switch): Take SWITCH_IGNORE into account, and earlier.
	(main): Set up and implement compare debug mode.
	(compare_debug_dump_opt_spec_function): New.
	(compare_debug_self_opt_spec_function): New.
	* toplev.c (process_options): Handle flag_gtoggle,
	flag_dump_final_insns.

for  gcc/cp/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* repo.c (finish_repo): Skip during -fcompare-debug-second.

for  gcc/ada/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* lib-writ.adb (flag_compare_debug): Import.
	(Write_ALI): Skip during -fcompare-debug-second.

for  gcc/fortran/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* options.c (gfc_post_options): Disable dump_parse_tree
	during -fcompare-debug-second.

for  gcc/objc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* objc-act.c (objc_init): Skip print_struct_values during
	-fcompare-debug-second.
	
Index: gcc/common.opt
===================================================================
--- gcc/common.opt.orig	2009-05-28 21:01:23.000000000 -0300
+++ gcc/common.opt	2009-05-28 21:01:24.000000000 -0300
@@ -384,6 +384,14 @@ fconserve-stack
 Common Var(flag_conserve_stack) Optimization
 Do not perform optimizations increasing noticeably stack usage
 
+fcompare-debug=
+Common JoinedOrMissing RejectNegative Var(flag_compare_debug_opt)
+-fcompare-debug[=<opts>] Compile with and without e.g. -gtoggle, and compare the final-insns dump
+
+fcompare-debug-second
+Common RejectNegative Var(flag_compare_debug)
+Run only the second compilation of -fcompare-debug
+
 fcprop-registers
 Common Report Var(flag_cprop_registers) Optimization
 Perform a register copy-propagation optimization pass
@@ -450,6 +458,10 @@ fdump-
 Common Joined RejectNegative
 -fdump-<type>	Dump various compiler internals to a file
 
+fdump-final-insns=
+Common RejectNegative Joined Var(flag_dump_final_insns)
+-fdump-final-insns=filename	Dump to filename the insns at the end of translation
+
 fdump-noaddr
 Common Report Var(flag_dump_noaddr)
 Suppress output of addresses in debugging dumps
@@ -1425,6 +1437,10 @@ gstabs+
 Common JoinedOrMissing Negative(gvms)
 Generate debug information in extended STABS format
 
+gtoggle
+Common Report Var(flag_gtoggle)
+Toggle debug information generation
+
 gvms
 Common JoinedOrMissing Negative(gxcoff)
 Generate debug information in VMS format
Index: gcc/final.c
===================================================================
--- gcc/final.c.orig	2009-05-28 05:33:38.000000000 -0300
+++ gcc/final.c	2009-05-28 21:01:24.000000000 -0300
@@ -4290,6 +4290,42 @@ static unsigned int
 rest_of_clean_state (void)
 {
   rtx insn, next;
+  FILE *final_output = NULL;
+  int save_unnumbered = flag_dump_unnumbered;
+  int save_noaddr = flag_dump_noaddr;
+
+  if (flag_dump_final_insns)
+    {
+      final_output = fopen (flag_dump_final_insns, "a");
+      if (!final_output)
+	{
+	  error ("could not open final insn dump file %qs: %s",
+		 flag_dump_final_insns, strerror (errno));
+	  flag_dump_final_insns = NULL;
+	}
+      else
+	{
+	  const char *aname;
+
+	  aname = (IDENTIFIER_POINTER
+		   (DECL_ASSEMBLER_NAME (current_function_decl)));
+	  fprintf (final_output, "\n;; Function (%s) %s\n\n", aname,
+	     cfun->function_frequency == FUNCTION_FREQUENCY_HOT
+	     ? " (hot)"
+	     : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED
+	     ? " (unlikely executed)"
+	     : "");
+
+	  flag_dump_noaddr = flag_dump_unnumbered = 1;
+
+	  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+	    if (LABEL_P (insn))
+	      INSN_UID (insn) = CODE_LABEL_NUMBER (insn);
+	    else
+	      INSN_UID (insn) = 0;
+
+	}
+    }
 
   /* It is very important to decompose the RTL instruction chain here:
      debug information keeps pointing into CODE_LABEL insns inside the function
@@ -4300,6 +4336,27 @@ rest_of_clean_state (void)
       next = NEXT_INSN (insn);
       NEXT_INSN (insn) = NULL;
       PREV_INSN (insn) = NULL;
+
+      if (final_output
+	  && (!NOTE_P (insn) ||
+	      (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION
+	       && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG
+	       && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END)))
+	print_rtl_single (final_output, insn);
+
+    }
+
+  if (final_output)
+    {
+      flag_dump_noaddr = save_noaddr;
+      flag_dump_unnumbered = save_unnumbered;
+
+      if (fclose (final_output))
+	{
+	  error ("could not close final insn dump file %qs: %s",
+		 flag_dump_final_insns, strerror (errno));
+	  flag_dump_final_insns = NULL;
+	}
     }
 
   /* In case the function was not output,
Index: gcc/gcc.c
===================================================================
--- gcc/gcc.c.orig	2009-05-28 05:33:38.000000000 -0300
+++ gcc/gcc.c	2009-05-29 04:14:50.000000000 -0300
@@ -387,6 +387,8 @@ static const char *replace_outfile_spec_
 static const char *version_compare_spec_function (int, const char **);
 static const char *include_spec_function (int, const char **);
 static const char *print_asm_header_spec_function (int, const char **);
+static const char *compare_debug_dump_opt_spec_function (int, const char **);
+static const char *compare_debug_self_opt_spec_function (int, const char **);
 
 /* The Specs Language
 
@@ -871,9 +873,11 @@ static const char *asm_options =
 
 static const char *invoke_as =
 #ifdef AS_NEEDS_DASH_FOR_PIPED_INPUT
-"%{!S:-o %|.s |\n as %(asm_options) %|.s %A }";
+"%{fcompare-debug=*:%:compare-debug-dump-opt()}\
+ %{!S:-o %|.s |\n as %(asm_options) %|.s %A }";
 #else
-"%{!S:-o %|.s |\n as %(asm_options) %m.s %A }";
+"%{fcompare-debug=*:%:compare-debug-dump-opt()}\
+ %{!S:-o %|.s |\n as %(asm_options) %m.s %A }";
 #endif
 
 /* Some compilers have limits on line lengths, and the multilib_select
@@ -1669,6 +1673,8 @@ static const struct spec_function static
   { "version-compare",		version_compare_spec_function },
   { "include",			include_spec_function },
   { "print-asm-header",		print_asm_header_spec_function },
+  { "compare-debug-dump-opt",	compare_debug_dump_opt_spec_function },
+  { "compare-debug-self-opt",	compare_debug_self_opt_spec_function },
 #ifdef EXTRA_SPEC_FUNCTIONS
   EXTRA_SPEC_FUNCTIONS
 #endif
@@ -3155,6 +3161,17 @@ static struct switchstr *switches;
 
 static int n_switches;
 
+int compare_debug;
+int compare_debug_second;
+
+const char *compare_debug_opt;
+
+static struct switchstr *switches_debug_check[2];
+
+static int n_switches_debug_check[2];
+
+static char *debug_check_temp_file[2];
+
 /* Language is one of three things:
 
    1) The name of a real programming language.
@@ -3744,6 +3761,38 @@ process_command (int argc, const char **
 	print_multi_os_directory = 1;
       else if (! strcmp (argv[i], "-print-sysroot-headers-suffix"))
 	print_sysroot_headers_suffix = 1;
+      else if (! strcmp (argv[i], "-fcompare-debug-second"))
+	{
+	  compare_debug_second = 1;
+	  n_switches++;
+	}
+      else if (! strcmp (argv[i], "-fno-compare-debug"))
+	{
+	  argv[i] = "-fcompare-debug=";
+	  goto compare_debug_with_arg;
+	}
+      else if (! strcmp (argv[i], "-fcompare-debug"))
+	{
+	  argv[i] = "-fcompare-debug=-gtoggle";
+	  goto compare_debug_with_arg;
+	}
+#define OPT "-fcompare-debug="
+      else if (! strncmp (argv[i], OPT, sizeof (OPT) - 1))
+	{
+	  const char *opt;
+	compare_debug_with_arg:
+	  opt = argv[i] + sizeof (OPT) - 1;
+#undef OPT
+	  if (*opt)
+	    compare_debug = 1;
+	  else
+	    compare_debug = -1;
+	  if (compare_debug < 0)
+	    compare_debug_opt = NULL;
+	  else
+	    compare_debug_opt = opt;
+	  n_switches++;
+	}
       else if (! strncmp (argv[i], "-Wa,", 4))
 	{
 	  int prev, j;
@@ -4095,6 +4144,29 @@ process_command (int argc, const char **
       use_pipes = 0;
     }
 
+  if (!compare_debug)
+    {
+      const char *gcd = getenv ("GCC_COMPARE_DEBUG");
+
+      if (gcd && gcd[0] == '-')
+	{
+	  compare_debug = 2;
+	  compare_debug_opt = gcd;
+	  n_switches++;
+	}
+      else if (gcd && *gcd && strcmp (gcd, "0"))
+	{
+	  compare_debug = 3;
+	  compare_debug_opt = "-gtoggle";
+	  n_switches++;
+	}
+    }
+  else if (compare_debug < 0)
+    {
+      compare_debug = 0;
+      gcc_assert (!compare_debug_opt);
+    }
+
   /* Set up the search paths.  We add directories that we expect to
      contain GNU Toolchain components before directories specified by
      the machine description so that we will find GNU components (like
@@ -4386,6 +4458,19 @@ process_command (int argc, const char **
   if (n_infiles == last_language_n_infiles && spec_lang != 0)
     error ("warning: '-x %s' after last input file has no effect", spec_lang);
 
+  if (compare_debug == 2 || compare_debug == 3)
+    {
+      switches[n_switches].part1 = concat ("fcompare-debug=",
+					   compare_debug_opt,
+					   NULL);
+      switches[n_switches].args = 0;
+      switches[n_switches].live_cond = 0;
+      switches[n_switches].validated = 0;
+      switches[n_switches].ordering = 0;
+      n_switches++;
+      compare_debug = 1;
+    }
+
   /* Ensure we only invoke each subprocess once.  */
   if (print_subprocess_help || print_help_list || print_version)
     {
@@ -4681,28 +4766,69 @@ do_self_spec (const char *spec)
 
   if (argbuf_index > 0)
     {
-      int i, first;
+      int i;
 
-      first = n_switches;
-      n_switches += argbuf_index;
-      switches = XRESIZEVEC (struct switchstr, switches, n_switches + 1);
+      switches = XRESIZEVEC (struct switchstr, switches,
+			     n_switches + argbuf_index + 1);
 
-      switches[n_switches] = switches[first];
       for (i = 0; i < argbuf_index; i++)
 	{
 	  struct switchstr *sw;
+	  const char *p = argbuf[i];
+	  int c = *p;
 
 	  /* Each switch should start with '-'.  */
-	  if (argbuf[i][0] != '-')
+	  if (c != '-')
 	    fatal ("switch '%s' does not start with '-'", argbuf[i]);
 
-	  sw = &switches[i + first];
-	  sw->part1 = &argbuf[i][1];
-	  sw->args = 0;
+	  p++;
+	  c = *p;
+
+	  sw = &switches[n_switches++];
+	  sw->part1 = p;
 	  sw->live_cond = 0;
 	  sw->validated = 0;
 	  sw->ordering = 0;
+
+	  /* Deal with option arguments in separate argv elements.  */
+	  if ((SWITCH_TAKES_ARG (c) > (p[1] != 0))
+	      || WORD_SWITCH_TAKES_ARG (p))
+	    {
+	      int j = 0;
+	      int n_args = WORD_SWITCH_TAKES_ARG (p);
+
+	      if (n_args == 0)
+		{
+		  /* Count only the option arguments in separate argv elements.  */
+		  n_args = SWITCH_TAKES_ARG (c) - (p[1] != 0);
+		}
+	      if (i + n_args >= argbuf_index)
+		fatal ("argument to '-%s' is missing", p);
+	      sw->args
+		= XNEWVEC (const char *, n_args + 1);
+	      while (j < n_args)
+		sw->args[j++] = argbuf[++i];
+	      /* Null-terminate the vector.  */
+	      sw->args[j] = 0;
+	    }
+	  else if (strchr (switches_need_spaces, c))
+	    {
+	      /* On some systems, ld cannot handle some options without
+		 a space.  So split the option from its argument.  */
+	      char *part1 = XNEWVEC (char, 2);
+	      part1[0] = c;
+	      part1[1] = '\0';
+
+	      sw->part1 = part1;
+	      sw->args = XNEWVEC (const char *, 2);
+	      sw->args[0] = xstrdup (p+1);
+	      sw->args[1] = 0;
+	    }
+	  else
+	    sw->args = 0;
 	}
+
+      switches[n_switches].part1 = 0;
     }
 }
 
@@ -4888,6 +5014,8 @@ do_spec_1 (const char *spec, int inswitc
 	      obstack_grow (&obstack, save_temps_prefix, save_temps_length);
 	    else
 	      obstack_grow (&obstack, input_basename, basename_length);
+	    if (compare_debug < 0)
+	      obstack_grow (&obstack, ".gk", 3);
 	    arg_going = 1;
 	    break;
 
@@ -4896,6 +5024,8 @@ do_spec_1 (const char *spec, int inswitc
 	      obstack_grow (&obstack, save_temps_prefix, save_temps_length);
 	    else
 	      obstack_grow (&obstack, input_basename, suffixed_basename_length);
+	    if (compare_debug < 0)
+	      obstack_grow (&obstack, ".gk", 3);
 	    arg_going = 1;
 	    break;
 
@@ -5041,6 +5171,12 @@ do_spec_1 (const char *spec, int inswitc
 		    suffix_length += strlen (TARGET_OBJECT_SUFFIX);
 		  }
 
+		if (compare_debug < 0)
+		  {
+		    suffix = concat (".gk", suffix, NULL);
+		    suffix_length += 3;
+		  }
+
 		/* If -save-temps=obj and -o were specified, use that for the
 		   temp file.  */
 		if (save_temps_length)
@@ -6131,18 +6267,19 @@ check_live_switch (int switchnum, int pr
   const char *name = switches[switchnum].part1;
   int i;
 
+  /* If we already processed this switch and determined if it was
+     live or not, return our past determination.  */
+  if (switches[switchnum].live_cond != 0)
+    return ((switches[switchnum].live_cond & SWITCH_LIVE) != 0
+	    && (switches[switchnum].live_cond & SWITCH_FALSE) == 0
+	    && (switches[switchnum].live_cond & SWITCH_IGNORE) == 0);
+
   /* In the common case of {<at-most-one-letter>*}, a negating
      switch would always match, so ignore that case.  We will just
      send the conflicting switches to the compiler phase.  */
   if (prefix_length >= 0 && prefix_length <= 1)
     return 1;
 
-  /* If we already processed this switch and determined if it was
-     live or not, return our past determination.  */
-  if (switches[switchnum].live_cond != 0)
-    return ((switches[switchnum].live_cond & SWITCH_LIVE) != 0
-	    && (switches[switchnum].live_cond & SWITCH_FALSE) == 0);
-
   /* Now search for duplicate in a manner that depends on the name.  */
   switch (*name)
     {
@@ -6511,6 +6648,43 @@ main (int argc, char **argv)
   for (i = 0; i < ARRAY_SIZE (driver_self_specs); i++)
     do_self_spec (driver_self_specs[i]);
 
+  if (compare_debug)
+    {
+      enum save_temps save;
+
+      if (!compare_debug_second)
+	{
+	  n_switches_debug_check[1] = n_switches;
+	  switches_debug_check[1] = XDUPVEC (struct switchstr, switches,
+					     n_switches + 1);
+
+	  do_self_spec ("%:compare-debug-self-opt()");
+	  n_switches_debug_check[0] = n_switches;
+	  switches_debug_check[0] = switches;
+
+	  n_switches = n_switches_debug_check[1];
+	  switches = switches_debug_check[1];
+	}
+
+      /* Avoid crash when computing %j in this early.  */
+      save = save_temps_flag;
+      save_temps_flag = SAVE_TEMPS_NONE;
+
+      compare_debug = -compare_debug;
+      do_self_spec ("%:compare-debug-self-opt()");
+
+      save_temps_flag = save;
+
+      if (!compare_debug_second)
+	{
+	  n_switches_debug_check[1] = n_switches;
+	  switches_debug_check[1] = switches;
+	  compare_debug = -compare_debug;
+	  n_switches = n_switches_debug_check[0];
+	  switches = switches_debug_check[0];
+	}
+    }
+
   /* If not cross-compiling, look for executables in the standard
      places.  */
   if (*cross_compile == '0')
@@ -6939,10 +7113,109 @@ warranty; not even for MERCHANTABILITY o
 	    }
 	  else
 	    {
+	      if (compare_debug)
+		{
+		  if (debug_check_temp_file[0])
+		    free (debug_check_temp_file[0]);
+		  debug_check_temp_file[0] = NULL;
+
+		  if (debug_check_temp_file[1])
+		    free (debug_check_temp_file[1]);
+		  debug_check_temp_file[1] = NULL;
+		}
+
 	      value = do_spec (input_file_compiler->spec);
 	      infiles[i].compiled = true;
 	      if (value < 0)
-		this_file_error = 1;
+		{
+		  this_file_error = 1;
+		}
+	      else if (compare_debug && debug_check_temp_file[0])
+		{
+		  FILE *temp[2];
+
+		  if (verbose_flag)
+		    error ("Recompiling with -fcompare-debug");
+
+		  compare_debug = -compare_debug;
+		  n_switches = n_switches_debug_check[1];
+		  switches = switches_debug_check[1];
+
+		  debug_check_temp_file[1] = NULL;
+		  value = do_spec (input_file_compiler->spec);
+
+		  compare_debug = -compare_debug;
+		  n_switches = n_switches_debug_check[0];
+		  switches = switches_debug_check[0];
+
+		  if (value < 0)
+		    {
+		      error ("during -fcompare-debug recompilation");
+		      this_file_error = 1;
+		    }
+
+		  gcc_assert (debug_check_temp_file[1]
+			      && strcmp (debug_check_temp_file[0],
+					 debug_check_temp_file[1]));
+
+		  temp[0] = fopen (debug_check_temp_file[0], "r");
+		  if (!temp[0])
+		    {
+		      error ("%s: could not open compare-debug file %s",
+			     input_filename, debug_check_temp_file[0]);
+		      this_file_error = 1;
+		    }
+		  temp[1] = fopen (debug_check_temp_file[1], "r");
+		  if (!temp[1])
+		    {
+		      error ("%s: could not open compare-debug file %s",
+			     input_filename, debug_check_temp_file[1]);
+		      this_file_error = 1;
+		    }
+
+		  free (debug_check_temp_file[1]);
+		  debug_check_temp_file[1] = NULL;
+		  free (debug_check_temp_file[0]);
+		  debug_check_temp_file[0] = NULL;
+
+		  if (verbose_flag)
+		    error ("Comparing final insns dumps");
+
+		  if (!this_file_error && temp[0] && temp[1])
+		    for (;;)
+		      {
+			int c0, c1;
+			c0 = fgetc (temp[0]);
+			c1 = fgetc (temp[1]);
+
+			if (c0 != c1)
+			  {
+			    error ("%s: -fcompare-debug failure",
+				   input_filename);
+			    this_file_error = 1;
+			    break;
+			  }
+
+			if (c0 == EOF)
+			  break;
+		      }
+
+		  if (temp[1])
+		    fclose (temp[1]);
+		  if (temp[0])
+		    fclose (temp[0]);
+		}
+
+	      if (compare_debug)
+		{
+		  if (debug_check_temp_file[0])
+		    free (debug_check_temp_file[0]);
+		  debug_check_temp_file[0] = NULL;
+
+		  if (debug_check_temp_file[1])
+		    free (debug_check_temp_file[1]);
+		  debug_check_temp_file[1] = NULL;
+		}
 	    }
 	}
 
@@ -8227,3 +8500,73 @@ print_asm_header_spec_function (int arg 
   fflush (stdout);
   return NULL;
 }
+
+/* %:compare-debug spec function.  Save the last argument, expected to
+   be the last -fdump-final-insns option, or generate a temporary.  */
+
+static const char *
+compare_debug_dump_opt_spec_function (int arg,
+				      const char **argv ATTRIBUTE_UNUSED)
+{
+  const char *ret;
+  char *name;
+  int which;
+
+  if (arg != 0)
+    fatal ("too many arguments to %%:compare-debug-dump-opt");
+
+  if (!compare_debug)
+    return NULL;
+
+  do_spec_2 ("%{fdump-final-insns=*:%*}");
+  do_spec_1 (" ", 0, NULL);
+
+  if (argbuf_index > 0)
+    {
+      name = xstrdup (argv[argbuf_index - 1]);
+      ret = NULL;
+    }
+  else
+    {
+#define OPT "-fdump-final-insns="
+      ret = "-fdump-final-insns=%g.gkd";
+
+      do_spec_2 (ret + sizeof (OPT) - 1);
+      do_spec_1 (" ", 0, NULL);
+#undef OPT
+
+      gcc_assert (argbuf_index > 0);
+
+      name = xstrdup (argbuf[argbuf_index - 1]);
+    }
+
+  which = compare_debug < 0;
+  debug_check_temp_file[which] = name;
+
+#if 0
+  error ("compare-debug: [%i]=\"%s\", ret %s", which, name, ret);
+#endif
+
+  return ret;
+}
+
+/* %:compare-debug spec function.  Save the name of the compare debug
+    file.  */
+
+static const char *
+compare_debug_self_opt_spec_function (int arg,
+				      const char **argv ATTRIBUTE_UNUSED)
+{
+  if (arg != 0)
+    fatal ("too many arguments to %%:compare-debug-opt");
+
+  if (compare_debug >= 0)
+    return NULL;
+
+  if (compare_debug > 0)
+    return compare_debug_opt;
+
+  return concat ("%<o* %<MD %<MMD %<MF* %<MG %<MP %<MQ* %<MT* \
+%<fdump-final-insns=* -w -S -o %j \
+%{!fcompare-debug-second:-fcompare-debug-second} ", compare_debug_opt, NULL);
+}
Index: gcc/toplev.c
===================================================================
--- gcc/toplev.c.orig	2009-05-28 05:33:38.000000000 -0300
+++ gcc/toplev.c	2009-05-28 21:01:24.000000000 -0300
@@ -1870,6 +1870,31 @@ process_options (void)
       profile_flag = 0;
     }
 
+  if (flag_gtoggle)
+    {
+      if (debug_info_level == DINFO_LEVEL_NONE)
+	debug_info_level = DINFO_LEVEL_NORMAL;
+      else
+	debug_info_level = DINFO_LEVEL_NONE;
+    }
+
+  if (flag_dump_final_insns)
+    {
+      FILE *final_output = fopen (flag_dump_final_insns, "w");
+      if (!final_output)
+	{
+	  error ("could not open final insn dump file %qs: %s",
+		 flag_dump_final_insns, strerror (errno));
+	  flag_dump_final_insns = NULL;
+	}
+      else if (fclose (final_output))
+	{
+	  error ("could not close zeroed insn dump file %qs: %s",
+		 flag_dump_final_insns, strerror (errno));
+	  flag_dump_final_insns = NULL;
+	}
+    }
+
   /* A lot of code assumes write_symbols == NO_DEBUG if the debugging
      level is 0.  */
   if (debug_info_level == DINFO_LEVEL_NONE)
Index: gcc/cp/repo.c
===================================================================
--- gcc/cp/repo.c.orig	2009-05-28 05:33:38.000000000 -0300
+++ gcc/cp/repo.c	2009-05-29 04:14:26.000000000 -0300
@@ -231,7 +231,7 @@ finish_repo (void)
   char *dir, *args;
   FILE *repo_file;
 
-  if (!flag_use_repository)
+  if (!flag_use_repository || flag_compare_debug)
     return;
 
   if (errorcount || sorrycount)
Index: gcc/ada/lib-writ.adb
===================================================================
--- gcc/ada/lib-writ.adb.orig	2009-05-28 05:33:38.000000000 -0300
+++ gcc/ada/lib-writ.adb	2009-05-28 21:01:25.000000000 -0300
@@ -197,6 +197,10 @@ package body Lib.Writ is
       Num_Sdep : Nat := 0;
       --  Number of active entries in Sdep_Table
 
+      flag_compare_debug : Int;
+      pragma Import (C, flag_compare_debug);
+      --  Import from toplev.c
+
       -----------------------
       -- Local Subprograms --
       -----------------------
@@ -800,7 +804,9 @@ package body Lib.Writ is
       --  We never write an ALI file if the original operating mode was
       --  syntax-only (-gnats switch used in compiler invocation line)
 
-      if Original_Operating_Mode = Check_Syntax then
+      if Original_Operating_Mode = Check_Syntax
+        or flag_compare_debug /= 0
+      then
          return;
       end if;
 
Index: gcc/fortran/options.c
===================================================================
--- gcc/fortran/options.c.orig	2009-05-28 05:33:38.000000000 -0300
+++ gcc/fortran/options.c	2009-05-28 21:01:25.000000000 -0300
@@ -246,6 +246,9 @@ gfc_post_options (const char **pfilename
   if (flag_bounds_check)
     gfc_option.rtcheck |= GFC_RTCHECK_BOUNDS;
 
+  if (flag_compare_debug)
+    gfc_option.dump_parse_tree = 0;
+
   /* Verify the input file name.  */
   if (!filename || strcmp (filename, "-") == 0)
     {
Index: gcc/objc/objc-act.c
===================================================================
--- gcc/objc/objc-act.c.orig	2009-05-28 05:33:38.000000000 -0300
+++ gcc/objc/objc-act.c	2009-05-28 21:01:25.000000000 -0300
@@ -550,7 +550,7 @@ objc_init (void)
 
   init_objc ();
 
-  if (print_struct_values)
+  if (print_struct_values && !flag_compare_debug)
     generate_struct_by_value_array ();
 
   return true;
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi.orig	2009-05-28 21:01:23.000000000 -0300
+++ gcc/doc/invoke.texi	2009-05-29 04:14:26.000000000 -0300
@@ -302,13 +302,15 @@ Objective-C and Objective-C++ Dialects}.
 -fdump-tree-vrp@r{[}-@var{n}@r{]} @gol
 -ftree-vectorizer-verbose=@var{n} @gol
 -fdump-tree-storeccp@r{[}-@var{n}@r{]} @gol
+-fdump-final-insns=@var{file} @gol
+-fcompare-debug@r{[}=@var{opts}@r{]}  -fcompare-debug-second @gol
 -feliminate-dwarf2-dups -feliminate-unused-debug-types @gol
 -feliminate-unused-debug-symbols -femit-class-debug-always @gol
 -fmem-report -fpre-ipa-mem-report -fpost-ipa-mem-report -fprofile-arcs @gol
 -frandom-seed=@var{string} -fsched-verbose=@var{n} @gol
 -fsel-sched-verbose -fsel-sched-dump-cfg -fsel-sched-pipelining-verbose @gol
 -ftest-coverage  -ftime-report -fvar-tracking @gol
--g  -g@var{level}  -gcoff -gdwarf-2 @gol
+-g  -g@var{level}  -gtoggle  -gcoff -gdwarf-2 @gol
 -ggdb  -gstabs  -gstabs+  -gvms  -gxcoff  -gxcoff+ @gol
 -fno-merge-debug-strings -fno-dwarf2-cfi-asm @gol
 -fdebug-prefix-map=@var{old}=@var{new} @gol
@@ -4363,6 +4365,61 @@ debug format is long obsolete, but the o
 Instead use an additional @option{-g@var{level}} option to change the
 debug level for DWARF2.
 
+@item -gtoggle
+@opindex gtoggle
+Turn off generation of debug info, if leaving out this option would have
+generated it, or turn it on at level 2 otherwise.  The position of this
+argument in the command line does not matter, it takes effect after all
+other options are processed, and it does so only once, no matter how
+many times it is given.  This is mainly intended to be used with
+@option{-fcompare-debug}.
+
+@item -fdump-final-insns=@var{file}
+@opindex fdump-final-insns=
+Dump the final internal representation (RTL) to @var{file}.
+
+@item -fcompare-debug@r{[}=@var{opts}@r{]}
+@opindex fcompare-debug
+@opindex fno-compare-debug
+If no error occurs during compilation, run the compiler a second time,
+adding @var{opts} and @option{-fcompare-debug-second} to the arguments
+passed to the second compilation.  Dump the final internal
+representation in both compilations, and print an error if they differ.
+
+If the equal sign is omitted, the default @option{-gtoggle} is used.
+
+The environment variable @env{GCC_COMPARE_DEBUG}, if defined, non-empty
+and nonzero, implicitly enables @option{-fcompare-debug}.  If
+@env{GCC_COMPARE_DEBUG} is defined to a string starting with a dash,
+then it is used for @var{opts}, otherwise the default @option{-gtoggle}
+is used.
+
+@option{-fcompare-debug=}, with the equal sign but without @var{opts},
+is equivalent to @option{-fno-compare-debug}, which disables the dumping
+of the final representation and the second compilation, preventing even
+@env{GCC_COMPARE_DEBUG} from taking effect.
+
+To verify full coverage during @option{-fcompare-debug} testing, set
+@env{GCC_COMPARE_DEBUG} to say @samp{-fcompare-debug-not-overridden},
+which GCC will reject as an invalid option in any actual compilation
+(rather than preprocessing, assembly or linking).  To get just a
+warning, setting @env{GCC_COMPARE_DEBUG} to @samp{-w%n-fcompare-debug
+not overridden} will do.
+
+@item -fcompare-debug-second
+@opindex fcompare-debug-second
+This option is implicitly passed to the compiler for the second
+compilation requested by @option{-fcompare-debug}, along with options to
+silence warnings, and omitting other options that would cause
+side-effect compiler outputs to files or to the standard output.  Dump
+files and preserved temporary files are renamed so as to contain the
+@code{.gk} additional extension during the second compilation, to avoid
+overwriting those generated by the first.
+
+When this option is passed to the compiler driver, it causes the
+@emph{first} compilation to be skipped, which makes it useful for little
+other than debugging the compiler proper.
+
 @item -feliminate-dwarf2-dups
 @opindex feliminate-dwarf2-dups
 Compress DWARF2 debugging information by eliminating duplicated

-- 
Alexandre Oliva, freedom fighter    http://FSFLA.org/~lxoliva/
You must be the change you wish to see in the world. -- Gandhi
Be Free! -- http://FSFLA.org/   FSF Latin America board member
Free Software Evangelist      Red Hat Brazil Compiler Engineer

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]