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]

Re: VTA merge - testsuite guality


testsuite-guality (16K) - (still small) debug info quality testsuite

Index: gcc/testsuite/gcc.dg/guality/guality.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/testsuite/gcc.dg/guality/guality.c	2009-06-05 05:46:34.000000000 -0300
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-options "-g" } */
+
+#include "guality.h"
+
+/* Some silly sanity checking.  */
+
+int
+main (int argc, char *argv[])
+{
+  int i = argc+1;
+  int j = argc-2;
+  int k = 5;
+
+  GUALCHKXPR (argc);
+  GUALCHKXPR (i);
+  GUALCHKXPR (j);
+  GUALCHKXPR (k);
+  GUALCHKXPR (&i);
+  GUALCHKFLA (argc);
+  GUALCHKFLA (i);
+  GUALCHKFLA (j);
+  GUALCHKXPR (i);
+  GUALCHKXPR (j);
+  GUALCHKXPRVAL ("k", 5, 1);
+  GUALCHKXPRVAL ("0x40", 64, 0);
+  /* GUALCHKXPRVAL ("0", 0, 0); *//* XFAIL */
+}
Index: gcc/testsuite/gcc.dg/guality/guality.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/testsuite/gcc.dg/guality/guality.h	2009-06-05 05:46:34.000000000 -0300
@@ -0,0 +1,306 @@
+/* Infrastructure to test the quality of debug information.
+   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+   Contributed by Alexandre Oliva <aoliva@redhat.com>.
+
+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 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or 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 COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+/* This is a first cut at checking that debug information matches
+   run-time.  The idea is to annotate programs with GUALCHK* macros
+   that guide the tests.
+
+   In the current implementation, all of the macros expand to function
+   calls.  On the one hand, this interferes with optimizations; on the
+   other hand, it establishes an optimization barrier and a clear
+   inspection point, where previous operations (as in the abstract
+   machine) should have been completed and have their effects visible,
+   and future operations shouldn't have started yet.
+
+   In the current implementation of guality_check(), we fork a child
+   process that runs gdb, attaches to the parent process (the one that
+   called guality_check), moves up one stack frame (to the caller of
+   guality_check) and then examines the given expression.
+
+   If it matches the expected value, we have a PASS.  If it differs,
+   we have a FAILure.  If it is missing, we'll have a FAIL or an
+   UNRESOLVED depending on whether the variable or expression might be
+   unavailable at that point, as indicated by the third argument.
+
+   We envision a future alternate implementation with two compilation
+   and execution cycles, say one that runs the program and uses the
+   macros to log expressions and expected values, another in which the
+   macros expand to nothing and the logs are used to guide a debug
+   session that tests the values.  How to identify the inspection
+   points in the second case is yet to be determined.  It is
+   recommended that GUALCHK* macros be by themselves in source lines,
+   so that __FILE__ and __LINE__ will be usable to identify them.
+*/
+
+/* Attach a debugger to the current process and verify that the string
+   EXPR, evaluated by the debugger, yields the long long number VAL.
+   If the debugger cannot compute the expression, say because the
+   variable is unavailable, this will count as an error, unless unkok
+   is nonzero.  */
+
+#define GUALCHKXPRVAL(expr, val, unkok) \
+  guality_check ((expr), (val), (unkok))
+
+/* Check that a debugger knows that EXPR evaluates to the run-time
+   value of EXPR.  Unknown values are marked as acceptable,
+   considering that EXPR may die right after this call.  This will
+   affect the generated code in that EXPR will be evaluated and forced
+   to remain live at least until right before the call to
+   guality_check, although not necessarily after the call.  */
+
+#define GUALCHKXPR(expr) \
+  GUALCHKXPRVAL (#expr, (long long)(expr), 1)
+
+/* Same as GUALCHKXPR, but issue an error if the variable is optimized
+   away.  */
+
+#define GUALCHKVAL(expr) \
+  GUALCHKXPRVAL (#expr, (long long)(expr), 0)
+
+/* Check that a debugger knows that EXPR evaluates to the run-time
+   value of EXPR.  Unknown values are marked as errors, because the
+   value of EXPR is forced to be available right after the call, for a
+   range of at least one instruction.  This will affect the generated
+   code, in that EXPR *will* be evaluated before and preserved until
+   after the call to guality_check.  */
+
+#define GUALCHKFLA(expr) do {					\
+    __typeof(expr) volatile __preserve_after;			\
+    __typeof(expr) __preserve_before = (expr);			\
+    GUALCHKXPRVAL (#expr, (long long)(__preserve_before), 0);	\
+    __preserve_after = __preserve_before;			\
+    asm ("" : : "m" (__preserve_after));			\
+  } while (0)
+
+/* GUALCHK is the simplest way to assert that debug information for an
+   expression matches its run-time value.  Whether to force the
+   expression live after the call, so as to flag incompleteness
+   errors, can be disabled by defining GUALITY_DONT_FORCE_LIVE_AFTER.
+   Setting it to -1, an error is issued for optimized out variables,
+   even though they are not forced live.  */
+
+#if ! GUALITY_DONT_FORCE_LIVE_AFTER
+#define GUALCHK(var) GUALCHKFLA(var)
+#elif GUALITY_DONT_FORCE_LIVE_AFTER < 0
+#define GUALCHK(var) GUALCHKVAL(var)
+#else
+#define GUALCHK(var) GUALCHKXPR(var)
+#endif
+
+/* The name of the GDB program, with arguments to make it quiet.  This
+   is GUALITY_GDB_DEFAULT GUALITY_GDB_ARGS by default, but it can be
+   overridden by setting the GUALITY_GDB environment variable, whereas
+   GUALITY_GDB_DEFAULT can be overridden by setting the
+   GUALITY_GDB_NAME environment variable.  */
+
+static const char *guality_gdb_command;
+#define GUALITY_GDB_DEFAULT "gdb"
+#define GUALITY_GDB_ARGS " -nx -nw --quiet > /dev/null 2>&1"
+
+/* Kinds of results communicated as exit status from child process
+   that runs gdb to the parent process that's being monitored.  */
+
+enum guality_counter { PASS, INCORRECT, INCOMPLETE };
+
+/* Count of passes and errors.  */
+
+static int guality_count[INCOMPLETE+1];
+
+/* If --guality-skip is given in the command line, all the monitoring,
+   forking and debugger-attaching action will be disabled.  This is
+   useful to run the monitor program within a debugger.  */
+
+static int guality_skip;
+
+/* This is a file descriptor to which we'll issue gdb commands to
+   probe and test.  */
+FILE *guality_gdb_input;
+
+/* This holds the line number where we're supposed to set a
+   breakpoint.  */
+int guality_breakpoint_line;
+
+/* GDB should set this to true once it's connected.  */
+int volatile guality_attached;
+
+/* This function is the main guality program.  It may actually be
+   defined as main, because we #define main to it afterwards.  Because
+   of this wrapping, guality_main may not have an empty argument
+   list.  */
+
+extern int guality_main (int argc, char *argv[]);
+
+static void __attribute__((noinline))
+guality_check (const char *name, long long value, int unknown_ok);
+
+/* Set things up, run guality_main, then print a summary and quit.  */
+
+int
+main (int argc, char *argv[])
+{
+  int i;
+  char *argv0 = argv[0];
+
+  guality_gdb_command = getenv ("GUALITY_GDB");
+  if (!guality_gdb_command)
+    {
+      guality_gdb_command = getenv ("GUALITY_GDB_NAME");
+      if (!guality_gdb_command)
+	guality_gdb_command = GUALITY_GDB_DEFAULT GUALITY_GDB_ARGS;
+      else
+	{
+	  int len = strlen (guality_gdb_command) + sizeof (GUALITY_GDB_ARGS);
+	  char *buf = __builtin_alloca (len);
+	  strcpy (buf, guality_gdb_command);
+	  strcat (buf, GUALITY_GDB_ARGS);
+	  guality_gdb_command = buf;
+	}
+    }
+
+  for (i = 1; i < argc; i++)
+    if (strcmp (argv[i], "--guality-skip") == 0)
+      guality_skip = 1;
+    else
+      break;
+
+  if (!guality_skip)
+    {
+      guality_gdb_input = popen (guality_gdb_command, "w");
+      guality_check (NULL, 0, 0);
+      fprintf (guality_gdb_input, "\
+set height 0\n\
+attach %i\n\
+b %i\n\
+set guality_attached = 1\n\
+continue\n\
+", (int)getpid (), guality_breakpoint_line);
+      fflush (guality_gdb_input);
+    }
+
+  argv[--i] = argv0;
+
+  guality_main (argc - i, argv + i);
+
+  i = guality_count[INCORRECT];
+
+  fprintf (stderr, "%s: %i PASS, %i FAIL, %i UNRESOLVED\n",
+	   i ? "FAIL" : "PASS",
+	   guality_count[PASS], guality_count[INCORRECT],
+	   guality_count[INCOMPLETE]);
+
+  return i;
+}
+
+#define main guality_main
+
+/* Fork a child process and attach a debugger to the parent to
+   evaluate NAME in the caller.  If it matches VALUE, we have a PASS;
+   if it's unknown and UNKNOWN_OK, we have an UNRESOLVED.  Otherwise,
+   it's a FAIL.  */
+
+static void __attribute__((noinline))
+guality_check (const char *name, long long value, int unknown_ok)
+{
+  int result;
+
+  if (guality_skip)
+    return;
+
+  {
+    volatile long long xvalue = -1;
+    volatile int unavailable = 0;
+    if (name)
+      {
+	/* The sequence below cannot distinguish an optimized away
+	   variable from one mapped to a non-lvalue zero.  */
+	fprintf (guality_gdb_input, "\
+up\n\
+set $value1 = 0\n\
+set $value1 = (%s)\n\
+set $value2 = -1\n\
+set $value2 = (%s)\n\
+set $value3 = $value1 - 1\n\
+set $value4 = $value1 + 1\n\
+set $value3 = (%s)++\n\
+set $value4 = --(%s)\n\
+down\n\
+set xvalue = $value1\n\
+set unavailable = $value1 != $value2 ? -1 : $value3 != $value4 ? 1 : 0\n\
+continue\n\
+", name, name, name, name);
+	fflush (guality_gdb_input);
+	while (!guality_attached)
+	  ;
+      }
+    else
+      {
+	guality_breakpoint_line = __LINE__ + 5;
+	return;
+      }
+    /* Do NOT add lines between the __LINE__ above and the line below,
+       without also adjusting the added constant to match.  */
+    if (!unavailable || (unavailable > 0 && xvalue))
+      {
+	if (xvalue == value)
+	  result = PASS;
+	else
+	  result = INCORRECT;
+      }
+    else
+      result = INCOMPLETE;
+    asm ("" : : "X" (name), "X" (value), "X" (unknown_ok), "m" (xvalue));
+    switch (result)
+      {
+      case PASS:
+	fprintf (stderr, "PASS: %s is %lli\n", name, value);
+	break;
+      case INCORRECT:
+	fprintf (stderr, "FAIL: %s is %lli, not %lli\n", name, xvalue, value);
+	break;
+      case INCOMPLETE:
+	fprintf (stderr, "%s: %s is %s, expected %lli\n",
+		 unknown_ok ? "UNRESOLVED" : "FAIL", name,
+		 unavailable < 0 ? "not computable" : "optimized away", value);
+	result = unknown_ok ? INCOMPLETE : INCORRECT;
+	break;
+      default:
+	abort ();
+      }
+  }
+
+  switch (result)
+    {
+    case PASS:
+    case INCORRECT:
+    case INCOMPLETE:
+      ++guality_count[result];
+      break;
+
+    default:
+      abort ();
+    }
+}
Index: gcc/testsuite/gcc.dg/guality/guality.exp
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/testsuite/gcc.dg/guality/guality.exp	2009-06-05 05:46:34.000000000 -0300
@@ -0,0 +1,7 @@
+# This harness is for tests that should be run at all optimisation levels.
+
+load_lib gcc-dg.exp
+
+dg-init
+gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.c]] ""
+dg-finish
Index: gcc/testsuite/gcc.dg/guality/example.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/testsuite/gcc.dg/guality/example.c	2009-06-05 05:46:34.000000000 -0300
@@ -0,0 +1,138 @@
+/* { dg-do run } */
+/* { dg-options "-g" } */
+
+#define GUALITY_DONT_FORCE_LIVE_AFTER -1
+
+#ifndef STATIC_INLINE
+#define STATIC_INLINE /*static*/
+#endif
+
+#include "guality.h"
+
+#include <assert.h>
+
+/* Test the debug info for the functions used in the VTA
+   presentation at the GCC Summit 2008.  */
+
+typedef struct list {
+  struct list *n;
+  int v;
+} elt, *node;
+
+STATIC_INLINE node
+find_val (node c, int v, node e)
+{
+  while (c < e)
+    {
+      GUALCHK (c);
+      GUALCHK (v);
+      GUALCHK (e);
+      if (c->v == v)
+	return c;
+      GUALCHK (c);
+      GUALCHK (v);
+      GUALCHK (e);
+      c++;
+    }
+  return NULL;
+}
+
+STATIC_INLINE node
+find_prev (node c, node w)
+{
+  while (c)
+    {
+      node o = c;
+      c = c->n;
+      GUALCHK (c);
+      GUALCHK (o);
+      GUALCHK (w);
+      if (c == w)
+	return o;
+      GUALCHK (c);
+      GUALCHK (o);
+      GUALCHK (w);
+    }
+  return NULL;
+}
+
+STATIC_INLINE node
+check_arr (node c, node e)
+{
+  if (c == e)
+    return NULL;
+  e--;
+  while (c < e)
+    {
+      GUALCHK (c);
+      GUALCHK (e);
+      if (c->v > (c+1)->v)
+	return c;
+      GUALCHK (c);
+      GUALCHK (e);
+      c++;
+    }
+  return NULL;
+}
+
+STATIC_INLINE node
+check_list (node c, node t)
+{
+  while (c != t)
+    {
+      node n = c->n;
+      GUALCHK (c);
+      GUALCHK (n);
+      GUALCHK (t);
+      if (c->v > n->v)
+	return c;
+      GUALCHK (c);
+      GUALCHK (n);
+      GUALCHK (t);
+      c = n;
+    }
+  return NULL;
+}
+
+struct list testme[] = {
+  { &testme[1],  2 },
+  { &testme[2],  3 },
+  { &testme[3],  5 },
+  { &testme[4],  7 },
+  { &testme[5], 11 },
+  { NULL, 13 },
+};
+
+int
+main (int argc, char *argv[])
+{
+  int n = sizeof (testme) / sizeof (*testme);
+  node first, last, begin, end, ret;
+
+  GUALCHKXPR (n);
+
+  begin = first = &testme[0];
+  last = &testme[n-1];
+  end = &testme[n];
+
+  GUALCHKXPR (first);
+  GUALCHKXPR (last);
+  GUALCHKXPR (begin);
+  GUALCHKXPR (end);
+
+  ret = find_val (begin, 13, end);
+  GUALCHK (ret);
+  assert (ret == last);
+
+  ret = find_prev (first, last);
+  GUALCHK (ret);
+  assert (ret == &testme[n-2]);
+
+  ret = check_arr (begin, end);
+  GUALCHK (ret);
+  assert (!ret);
+
+  ret = check_list (first, last);
+  GUALCHK (ret);
+  assert (!ret);
+}
Index: gcc/testsuite/lib/gcc-dg.exp
===================================================================
--- gcc/testsuite/lib/gcc-dg.exp.orig	2009-06-05 05:46:45.000000000 -0300
+++ gcc/testsuite/lib/gcc-dg.exp	2009-06-05 05:46:55.000000000 -0300
@@ -440,11 +440,15 @@ proc cleanup-dump { suffix } {
     # The name might include a list of options; extract the file name.
     set src [file tail [lindex $testcase 0]]
     remove-build-file "[file tail $src].$suffix"
+    # -fcompare-debug dumps
+    remove-build-file "[file tail $src].gk.$suffix"
 
     # Clean up dump files for additional source files.
     if [info exists additional_sources] {
 	foreach srcfile $additional_sources {
 	    remove-build-file "[file tail $srcfile].$suffix"
+	    # -fcompare-debug dumps
+	    remove-build-file "[file tail $srcfile].gk.$suffix"
 	}
     }
 }
@@ -459,7 +463,7 @@ proc cleanup-saved-temps { args } {
     set suffixes {}
 
     # add the to-be-kept suffixes
-    foreach suffix {".ii" ".i" ".s"} {
+    foreach suffix {".ii" ".i" ".s" ".gkd"} {
 	if {[lsearch $args $suffix] < 0} {
 	    lappend suffixes $suffix
 	}
@@ -471,6 +475,8 @@ proc cleanup-saved-temps { args } {
     upvar 2 name testcase
     foreach suffix $suffixes {
 	remove-build-file "[file rootname [file tail $testcase]]$suffix"
+	# -fcompare-debug dumps
+	remove-build-file "[file rootname [file tail $testcase]].gk$suffix"
     }
 
     # Clean up saved temp files for additional source files.
@@ -478,6 +484,8 @@ proc cleanup-saved-temps { args } {
 	foreach srcfile $additional_sources {
 	    foreach suffix $suffixes {
 		remove-build-file "[file rootname [file tail $srcfile]]$suffix"
+		# -fcompare-debug dumps
+		remove-build-file "[file rootname [file tail $srcfile]].gk$suffix"
 	    }
 	}
     }
-- 
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]