public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 00/17] RFC: Addding a unit testing framework to gcc
@ 2015-06-10 15:10 David Malcolm
  2015-06-10 15:10 ` [PATCH 09/17] Add test-hash-set.c to gcc/unittests David Malcolm
                   ` (18 more replies)
  0 siblings, 19 replies; 176+ messages in thread
From: David Malcolm @ 2015-06-10 15:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

Our current test suite is rather coarse-grained, acting at the level
of running gcc subprocesses, and verifying externally-visible
properties:
  - Did the compile succeed?
  - Was a particular dumpfile emitted, containing something matching
    some regex?
  - Does the generated code run and exit gracefully?
etc

The strength of this approach is that we have good "integration"
coverage: we know that the compiler runs and generates good code.
However it's slow, and doesn't allow very precise control over what
properties we can assert.

The following patch kit adds a suite of unit tests to gcc, aimed at
giving test coverage for properties that are difficult to test for
in the current system.  For example, there are tests of ggc to
verify that gengtype is doing sane things, of various container
classes (vec, hash_map, hash_set) and of wide-int.  Some of the
tests are rather "placeholdery" e.g. the tests of folding trees,
where there's plenty of room for adding new testcases.

I've split them up into multiple patches for ease of review, but
they all stand together.

I picked the Google Test framework:
  http://code.google.com/p/googletest/

I didn't do a very thorough survey of C++ test frameworks; I picked
this one as it's used by several very large projects (including
LLVM [1]), and is actively maintained.  Working with it has largely been
a pleasant experience: it generates good error messages when tests
fail (e.g. with enough information so that I can click on failures
in Emacs and have it go to the failing test), and is sane to work
with in gdb.  The log is easy to read; I've added an example to
the end of this mail.  It supports parameterizing testcases across
multiple types (I use this for testing wide-int).

The only other "framework" I've used has been the DejaGnu unittest
header, which I use for the jit testsuite; I can't recommend it (it's
a pain to use, and I've had to extend it repeatedly to get basic
functionality like string equality assertions).

The testsuite is intended to be very fast, all in one process, and it
takes less than a second to run; it fact, the time is dominated by a
single very slow test, which takes 300-400ms to run, but which could
be sped up [2]; other than that, it takes about 10ms to run.

Structurally, the patches add a "unittests" frontend: this is rather
analogous to libgccjit.so: it's a dummy frontend.  The
unittests/Make-lang.in builds a libgccunittests.so, which does
nothing, stubbing out the frontend hooks, but provides a DSO holding
the code to be tested.

libgccunittests.so is then linked into a "unittests.exe" binary, which
holds the actual testcases.  An advantage of this separation is that
although linking libgccunittests.so is rather slow (like linking "cc1"
etc), unittests.exe is very fast to link, so that it's very fast to
hack on individual tests without needing to relink "everything" for
each edit.

Of course, this means that we can't unittest the real frontends this
way (but we couldn't before, and maybe we can find a route to doing
this).

I have the Make-lang.in implementing the "unittests" target so that
it builds and *runs* the unit tests i.e. if you do a "make", the
unittests are run (rather than just on a "make check").  Given how
fast they are (especially relative to "make check", the only issue
I can see with this is the output log spew).  One nice thing about
doing it there is that it can be run at each stage of a bootstrap,
so hopefully we fail earlier when we're going to fail.

I marked it in config-lang.in as
  build_by_default="no"
so you have to opt-in to building it by adding "unittests" to the
  --enable-languages=
configure options.

The split of the bulk of the link into a libgccjitunittests.so
means that it also requires the
  --enable-host-shared
configure-time option.

It doesn't yet bootstrap; the link fails with:
test-folding.o: In function `testing::AssertionResult testing::internal::CmpHelperNE<tree_node*, tree_node*>(char const*, char const*, tree_node* const&, tree_node* const&)':
test-folding.c:(.text._ZN7testing8internal11CmpHelperNEIP9tree_nodeS3_EENS_15AssertionResultEPKcS6_RKT_RKT0_[_ZN7testing8internal11CmpHelperNEIP9tree_nodeS3_EENS_15AssertionResultEPKcS6_RKT_RKT0_]+0x26e): undefined reference to `testing::internal::StringStreamToString(std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >*)'

though this was using a system copy of gtest
(is this due to the C++ stdlib ABI change?  it seems to only affect
tests using EXPECT_STREQ, and if I hack them out, it seems to work).
(perhaps we'd need to bundle our own copy of gtest?)

Here's a sample log (and it's sanely color-coded if you run it at
a tty):

$ make unittests
[==========] Running 56 tests from 16 test cases.
[----------] Global test environment set-up.
[----------] 6 tests from ggc_test
[ RUN      ] ggc_test.tree_marking
[       OK ] ggc_test.tree_marking (0 ms)
[ RUN      ] ggc_test.custom_struct
[       OK ] ggc_test.custom_struct (0 ms)
[ RUN      ] ggc_test.finalization
[       OK ] ggc_test.finalization (0 ms)
[ RUN      ] ggc_test.deletable_global
[       OK ] ggc_test.deletable_global (1 ms)
[ RUN      ] ggc_test.inheritance
[       OK ] ggc_test.inheritance (0 ms)
[ RUN      ] ggc_test.chain_next
[       OK ] ggc_test.chain_next (326 ms)
[----------] 6 tests from ggc_test (327 ms total)

[----------] 5 tests from bitmap_test
[ RUN      ] bitmap_test.gc_alloc
[       OK ] bitmap_test.gc_alloc (0 ms)
[ RUN      ] bitmap_test.set_range
[       OK ] bitmap_test.set_range (0 ms)
[ RUN      ] bitmap_test.clear_bit_in_middle
[       OK ] bitmap_test.clear_bit_in_middle (0 ms)
[ RUN      ] bitmap_test.copying
[       OK ] bitmap_test.copying (0 ms)
[ RUN      ] bitmap_test.bitmap_single_bit_set_p
[       OK ] bitmap_test.bitmap_single_bit_set_p (0 ms)
[----------] 5 tests from bitmap_test (0 ms total)

[----------] 3 tests from cfg_test
[ RUN      ] cfg_test.linear_chain
[       OK ] cfg_test.linear_chain (1 ms)
[ RUN      ] cfg_test.diamond
[       OK ] cfg_test.diamond (0 ms)
[ RUN      ] cfg_test.fully_connected
[       OK ] cfg_test.fully_connected (0 ms)
[----------] 3 tests from cfg_test (1 ms total)

[----------] 1 test from tree_folding_test
[ RUN      ] tree_folding_test.arithmetic_folding
[       OK ] tree_folding_test.arithmetic_folding (0 ms)
[----------] 1 test from tree_folding_test (0 ms total)

[----------] 2 tests from function_test
[ RUN      ] function_test.fndecl_int_void
[       OK ] function_test.fndecl_int_void (0 ms)
[ RUN      ] function_test.fndecl_float_intchar
[       OK ] function_test.fndecl_float_intchar (0 ms)
[----------] 2 tests from function_test (0 ms total)

[----------] 4 tests from representation_test
[ RUN      ] representation_test.gimplification
[       OK ] representation_test.gimplification (0 ms)
[ RUN      ] representation_test.building_cfg
[       OK ] representation_test.building_cfg (0 ms)
[ RUN      ] representation_test.conversion_to_ssa
[       OK ] representation_test.conversion_to_ssa (0 ms)
[ RUN      ] representation_test.expansion_to_rtl
[       OK ] representation_test.expansion_to_rtl (6 ms)
[----------] 4 tests from representation_test (6 ms total)

[----------] 5 tests from gimple_test
[ RUN      ] gimple_test.assign_single
[       OK ] gimple_test.assign_single (0 ms)
[ RUN      ] gimple_test.assign_binop
[       OK ] gimple_test.assign_binop (0 ms)
[ RUN      ] gimple_test.nop_stmt
[       OK ] gimple_test.nop_stmt (0 ms)
[ RUN      ] gimple_test.return_stmt
[       OK ] gimple_test.return_stmt (0 ms)
[ RUN      ] gimple_test.return_without_value
[       OK ] gimple_test.return_without_value (0 ms)
[----------] 5 tests from gimple_test (0 ms total)

[----------] 1 test from hash_map_test
[ RUN      ] hash_map_test.map_of_strings_to_int
[       OK ] hash_map_test.map_of_strings_to_int (0 ms)
[----------] 1 test from hash_map_test (0 ms total)

[----------] 1 test from hash_set_test
[ RUN      ] hash_set_test.set_of_strings
[       OK ] hash_set_test.set_of_strings (0 ms)
[----------] 1 test from hash_set_test (0 ms total)

[----------] 4 tests from location_test
[ RUN      ] location_test.accessing_ordinary_linemaps
[       OK ] location_test.accessing_ordinary_linemaps (0 ms)
[ RUN      ] location_test.unknown_location
[       OK ] location_test.unknown_location (0 ms)
[ RUN      ] location_test.builtins
[       OK ] location_test.builtins (0 ms)
[ RUN      ] location_test.reading_source_line
[       OK ] location_test.reading_source_line (0 ms)
[----------] 4 tests from location_test (0 ms total)

[----------] 2 tests from rtl_test
[ RUN      ] rtl_test.test_single_set
[       OK ] rtl_test.test_single_set (0 ms)
[ RUN      ] rtl_test.uncond_jump
[       OK ] rtl_test.uncond_jump (0 ms)
[----------] 2 tests from rtl_test (0 ms total)

[----------] 3 tests from tree_test
[ RUN      ] tree_test.integer_constants
[       OK ] tree_test.integer_constants (0 ms)
[ RUN      ] tree_test.identifiers
[       OK ] tree_test.identifiers (0 ms)
[ RUN      ] tree_test.labels
[       OK ] tree_test.labels (0 ms)
[----------] 3 tests from tree_test (0 ms total)

[----------] 10 tests from vec_test
[ RUN      ] vec_test.quick_push
[       OK ] vec_test.quick_push (0 ms)
[ RUN      ] vec_test.safe_push
[       OK ] vec_test.safe_push (0 ms)
[ RUN      ] vec_test.truncate
[       OK ] vec_test.truncate (0 ms)
[ RUN      ] vec_test.safe_grow_cleared
[       OK ] vec_test.safe_grow_cleared (0 ms)
[ RUN      ] vec_test.pop
[       OK ] vec_test.pop (0 ms)
[ RUN      ] vec_test.safe_insert
[       OK ] vec_test.safe_insert (0 ms)
[ RUN      ] vec_test.ordered_remove
[       OK ] vec_test.ordered_remove (0 ms)
[ RUN      ] vec_test.unordered_remove
[       OK ] vec_test.unordered_remove (0 ms)
[ RUN      ] vec_test.block_remove
[       OK ] vec_test.block_remove (0 ms)
[ RUN      ] vec_test.qsort
[       OK ] vec_test.qsort (0 ms)
[----------] 10 tests from vec_test (1 ms total)

[----------] 3 tests from wide_int_test/0, where TypeParam = <type>
[ RUN      ] wide_int_test/0.test_printing
[       OK ] wide_int_test/0.test_printing (0 ms)
[ RUN      ] wide_int_test/0.test_ops
[       OK ] wide_int_test/0.test_ops (0 ms)
[ RUN      ] wide_int_test/0.test_comparisons
[       OK ] wide_int_test/0.test_comparisons (0 ms)
[----------] 3 tests from wide_int_test/0 (0 ms total)

[----------] 3 tests from wide_int_test/1, where TypeParam = <type>
[ RUN      ] wide_int_test/1.test_printing
[       OK ] wide_int_test/1.test_printing (0 ms)
[ RUN      ] wide_int_test/1.test_ops
[       OK ] wide_int_test/1.test_ops (0 ms)
[ RUN      ] wide_int_test/1.test_comparisons
[       OK ] wide_int_test/1.test_comparisons (0 ms)
[----------] 3 tests from wide_int_test/1 (0 ms total)

[----------] 3 tests from wide_int_test/2, where TypeParam = <type>
[ RUN      ] wide_int_test/2.test_printing
[       OK ] wide_int_test/2.test_printing (0 ms)
[ RUN      ] wide_int_test/2.test_ops
[       OK ] wide_int_test/2.test_ops (0 ms)
[ RUN      ] wide_int_test/2.test_comparisons
[       OK ] wide_int_test/2.test_comparisons (0 ms)
[----------] 3 tests from wide_int_test/2 (0 ms total)

[----------] Global test environment tear-down
[==========] 56 tests from 16 test cases ran. (338 ms total)
[  PASSED  ] 56 tests.

Thoughts?
Dave

[1] though it's not clear to me if LLVM is actually still using it;
see e.g. http://blog.llvm.org/2009/12/lit-it.html
[2] the test of chain_next/chain_prev in test-ggc.c, which needed
a very large linked list in order to reliably overflow the stack on
my box; perhaps this could be eliminated by adding something to
libiberty to shrink the stack size?

David Malcolm (17):
  Add Make-lang.in and config-lang.in to gcc/unittests
  Add test-bitmap.c to gcc/unittests
  Add test-cfg.c to gcc/unittests
  Add test-folding.c to gcc/unittests
  Add test-functions.c to gcc/unittests
  Add test-ggc.c to gcc/unittests
  Add test-gimple.c to gcc/unittests
  Add test-hash-map.c to gcc/unittests
  Add test-hash-set.c to gcc/unittests
  Add test-locations.c to gcc/unittests
  Add test-rtl.c to gcc/unittests
  Add test-tree.c to gcc/unittests
  Add test-vec.c to gcc/unittests
  Add test-wide-int.c to gcc/unittests
  Add unittests-frontend.c to gcc/unittests
  Add unittests-main.c to gcc/unittests
  toplev.c: move location_adhoc_data_fini call

 gcc/toplev.c                       |   3 +-
 gcc/unittests/Make-lang.in         | 200 ++++++++++++
 gcc/unittests/config-lang.in       |  34 ++
 gcc/unittests/test-bitmap.c        | 117 +++++++
 gcc/unittests/test-cfg.c           | 319 +++++++++++++++++++
 gcc/unittests/test-folding.c       | 121 +++++++
 gcc/unittests/test-functions.c     | 634 +++++++++++++++++++++++++++++++++++++
 gcc/unittests/test-ggc.c           | 292 +++++++++++++++++
 gcc/unittests/test-gimple.c        | 179 +++++++++++
 gcc/unittests/test-hash-map.c      |  78 +++++
 gcc/unittests/test-hash-set.c      |  54 ++++
 gcc/unittests/test-locations.c     | 148 +++++++++
 gcc/unittests/test-rtl.c           |  94 ++++++
 gcc/unittests/test-tree.c          | 102 ++++++
 gcc/unittests/test-vec.c           | 162 ++++++++++
 gcc/unittests/test-wide-int.c      | 186 +++++++++++
 gcc/unittests/unittests-frontend.c | 250 +++++++++++++++
 gcc/unittests/unittests-main.c     | 108 +++++++
 18 files changed, 3080 insertions(+), 1 deletion(-)
 create mode 100644 gcc/unittests/Make-lang.in
 create mode 100644 gcc/unittests/config-lang.in
 create mode 100644 gcc/unittests/test-bitmap.c
 create mode 100644 gcc/unittests/test-cfg.c
 create mode 100644 gcc/unittests/test-folding.c
 create mode 100644 gcc/unittests/test-functions.c
 create mode 100644 gcc/unittests/test-ggc.c
 create mode 100644 gcc/unittests/test-gimple.c
 create mode 100644 gcc/unittests/test-hash-map.c
 create mode 100644 gcc/unittests/test-hash-set.c
 create mode 100644 gcc/unittests/test-locations.c
 create mode 100644 gcc/unittests/test-rtl.c
 create mode 100644 gcc/unittests/test-tree.c
 create mode 100644 gcc/unittests/test-vec.c
 create mode 100644 gcc/unittests/test-wide-int.c
 create mode 100644 gcc/unittests/unittests-frontend.c
 create mode 100644 gcc/unittests/unittests-main.c

-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 09/17] Add test-hash-set.c to gcc/unittests
  2015-06-10 15:10 [PATCH 00/17] RFC: Addding a unit testing framework to gcc David Malcolm
@ 2015-06-10 15:10 ` David Malcolm
  2015-06-10 15:10 ` [PATCH 01/17] Add Make-lang.in and config-lang.in " David Malcolm
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-06-10 15:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/unittests/ChangeLog:
	* test-hash-set.c: New file.
---
 gcc/unittests/test-hash-set.c | 54 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)
 create mode 100644 gcc/unittests/test-hash-set.c

diff --git a/gcc/unittests/test-hash-set.c b/gcc/unittests/test-hash-set.c
new file mode 100644
index 0000000..3d6f0b4
--- /dev/null
+++ b/gcc/unittests/test-hash-set.c
@@ -0,0 +1,54 @@
+/* Unit tests for hash-set.h.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 <gtest/gtest.h>
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+
+namespace {
+
+TEST (hash_set_test, set_of_strings)
+{
+  hash_set <const char *> s;
+  EXPECT_EQ (0, s.elements ());
+
+  const char *red = "red";
+  const char *green = "green";
+  const char *blue = "blue";
+
+  EXPECT_EQ (false, s.contains (red));
+
+  /* Populate the hash_set.  */
+  EXPECT_EQ (false, s.add (red));
+  EXPECT_EQ (false, s.add (green));
+  EXPECT_EQ (false, s.add (blue));
+
+  /* Verify that the values are now within the set.  */
+  EXPECT_EQ (true, s.contains (red));
+  EXPECT_EQ (true, s.contains (green));
+  EXPECT_EQ (true, s.contains (blue));
+}
+
+}  /* anon namespace.  */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 04/17] Add test-folding.c to gcc/unittests
  2015-06-10 15:10 [PATCH 00/17] RFC: Addding a unit testing framework to gcc David Malcolm
                   ` (3 preceding siblings ...)
  2015-06-10 15:10 ` [PATCH 11/17] Add test-rtl.c " David Malcolm
@ 2015-06-10 15:10 ` David Malcolm
  2015-06-10 15:10 ` [PATCH 10/17] Add test-locations.c " David Malcolm
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-06-10 15:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/unittests/ChangeLog:
	* test-folding.c: New file.
---
 gcc/unittests/test-folding.c | 121 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 121 insertions(+)
 create mode 100644 gcc/unittests/test-folding.c

diff --git a/gcc/unittests/test-folding.c b/gcc/unittests/test-folding.c
new file mode 100644
index 0000000..277acea
--- /dev/null
+++ b/gcc/unittests/test-folding.c
@@ -0,0 +1,121 @@
+/* Unit tests for GCC's expression folding.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 <gtest/gtest.h>
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "hard-reg-set.h"
+#include "input.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "gimple-expr.h"
+#include "toplev.h"
+#include "print-tree.h"
+#include "tree-iterator.h"
+#include "gimplify.h"
+#include "tree-cfg.h"
+#include "fold-const.h"
+
+namespace {
+
+/* A test fixture for writing tests of folding trees.  */
+class tree_folding_test : public ::testing::Test
+{
+ protected:
+  void
+  assert_binop_folds_to_const (tree lhs, enum tree_code code, tree rhs,
+			       tree constant)
+  {
+    EXPECT_EQ (constant, fold_build2 (code, TREE_TYPE (lhs), lhs, rhs));
+  }
+
+  void
+  assert_binop_folds_to_nonlvalue (tree lhs, enum tree_code code, tree rhs,
+				   tree wrapped_expr)
+  {
+    tree result = fold_build2 (code, TREE_TYPE (lhs), lhs, rhs);
+    EXPECT_NE (wrapped_expr, result);
+    EXPECT_EQ (NON_LVALUE_EXPR, TREE_CODE (result));
+    EXPECT_EQ (wrapped_expr, TREE_OPERAND (result, 0));
+  }
+};
+
+TEST_F (tree_folding_test, arithmetic_folding)
+{
+  tree type = integer_type_node;
+  tree x = create_tmp_var_raw (type, "x");
+  tree zero = build_zero_cst (type);
+  tree one = build_int_cst (type, 1);
+
+  /* Addition.  */
+  /* 1 <-- (0 + 1) */
+  assert_binop_folds_to_const (zero, PLUS_EXPR, one,
+			       one);
+  assert_binop_folds_to_const (one, PLUS_EXPR, zero,
+			       one);
+
+  /* (nonlvalue)x <-- (x + 0) */
+  assert_binop_folds_to_nonlvalue (x, PLUS_EXPR, zero,
+				   x);
+
+  /* Subtraction.  */
+  /* 0 <-- (x - x) */
+  assert_binop_folds_to_const (x, MINUS_EXPR, x,
+			       zero);
+  assert_binop_folds_to_nonlvalue (x, MINUS_EXPR, zero,
+				   x);
+
+  /* Multiplication.  */
+  /* 0 <-- (x * 0) */
+  assert_binop_folds_to_const (x, MULT_EXPR, zero,
+			       zero);
+
+  /* (nonlvalue)x <-- (x * 1) */
+  assert_binop_folds_to_nonlvalue (x, MULT_EXPR, one,
+				   x);
+}
+
+}  // anon namespace
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 10/17] Add test-locations.c to gcc/unittests
  2015-06-10 15:10 [PATCH 00/17] RFC: Addding a unit testing framework to gcc David Malcolm
                   ` (4 preceding siblings ...)
  2015-06-10 15:10 ` [PATCH 04/17] Add test-folding.c " David Malcolm
@ 2015-06-10 15:10 ` David Malcolm
  2015-06-10 15:10 ` [PATCH 05/17] Add test-functions.c " David Malcolm
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-06-10 15:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/unittests/ChangeLog:
	* test-locations.c: New file.
---
 gcc/unittests/test-locations.c | 148 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 148 insertions(+)
 create mode 100644 gcc/unittests/test-locations.c

diff --git a/gcc/unittests/test-locations.c b/gcc/unittests/test-locations.c
new file mode 100644
index 0000000..7c93594
--- /dev/null
+++ b/gcc/unittests/test-locations.c
@@ -0,0 +1,148 @@
+/* Unit tests for GCC's source location-handling (and thus libcpp).
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 <gtest/gtest.h>
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+
+namespace {
+
+/* Fixture for testing location-handling.
+   Creates some pre-canned location_t values.  */
+
+class location_test : public ::testing::Test
+{
+ protected:
+  location_test ()
+  {
+    /* Build a simple linemap describing some locations. */
+    linemap_add (line_table, LC_ENTER, false, "foo.c", 0);
+
+    linemap_line_start (line_table, 1, 100);
+    loc_a = linemap_position_for_column (line_table, 1);
+    loc_b = linemap_position_for_column (line_table, 23);
+
+    linemap_line_start (line_table, 2, 100);
+    loc_c = linemap_position_for_column (line_table, 1);
+    loc_d = linemap_position_for_column (line_table, 17);
+
+    /* Example of a very long line.  */
+    linemap_line_start (line_table, 3, 2000);
+    loc_e = linemap_position_for_column (line_table, 700);
+
+    linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+
+    /* Multiple files.  */
+    linemap_add (line_table, LC_ENTER, false, "bar.c", 0);
+    linemap_line_start (line_table, 1, 200);
+    loc_f = linemap_position_for_column (line_table, 150);
+    linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+  }
+
+  /* Verify the result of LOCATION_FILE/LOCATION_LINE/LOCATION_COLUMN
+     on LOC.  */
+  void
+  expect_loceq (const char *exp_filename,
+		int exp_linenum,
+		int exp_colnum,
+		location_t loc)
+  {
+    EXPECT_STREQ (exp_filename, LOCATION_FILE (loc));
+    EXPECT_EQ (exp_linenum, LOCATION_LINE (loc));
+    EXPECT_EQ (exp_colnum, LOCATION_COLUMN (loc));
+  }
+
+  location_t loc_a;
+  location_t loc_b;
+  location_t loc_c;
+  location_t loc_d;
+  location_t loc_e;
+  location_t loc_f;
+};
+
+/* Verify basic operation of ordinary linemaps.  */
+
+TEST_F (location_test, accessing_ordinary_linemaps)
+{
+  /* Verify that we can recover the location info.  */
+  expect_loceq ("foo.c", 1, 1, loc_a);
+  expect_loceq ("foo.c", 1, 23, loc_b);
+  expect_loceq ("foo.c", 2, 1, loc_c);
+  expect_loceq ("foo.c", 2, 17, loc_d);
+  expect_loceq ("foo.c", 3, 700, loc_e);
+  expect_loceq ("bar.c", 1, 150, loc_f);
+}
+
+TEST_F (location_test, unknown_location)
+{
+  EXPECT_EQ (NULL, LOCATION_FILE (UNKNOWN_LOCATION));
+  EXPECT_EQ (0, LOCATION_LINE (UNKNOWN_LOCATION));
+  EXPECT_EQ (0, LOCATION_COLUMN (UNKNOWN_LOCATION));
+}
+
+TEST_F (location_test, builtins)
+{
+  expect_loceq ("<built-in>", 0, 0, BUILTINS_LOCATION);
+  EXPECT_PRED1 (is_location_from_builtin_token, BUILTINS_LOCATION);
+  EXPECT_FALSE (is_location_from_builtin_token (loc_a));
+}
+
+/* Verify reading of input files (e.g. for caret-based diagnostics.  */
+
+TEST_F (location_test, reading_source_line)
+{
+  /* We will read *this* source file, using __FILE__.
+     Here is some specific text to read and test for:
+     The quick brown fox jumps over the lazy dog.  */
+  const int linenum_after_test_message = __LINE__;
+
+  /* Locate the precanned text above.  */
+  expanded_location xloc;
+  xloc.file = __FILE__;
+  xloc.line = linenum_after_test_message - 1;
+  xloc.column = 0;
+
+  int line_size;
+  const char *source_line = location_get_source_line (xloc, &line_size);
+  EXPECT_TRUE (source_line != NULL);
+  EXPECT_STREQ ("     The quick brown fox jumps over the lazy dog.  */",
+		source_line);
+  EXPECT_EQ (53, line_size);
+}
+
+} /* anon namespace. */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 07/17] Add test-gimple.c to gcc/unittests
  2015-06-10 15:10 [PATCH 00/17] RFC: Addding a unit testing framework to gcc David Malcolm
                   ` (8 preceding siblings ...)
  2015-06-10 15:10 ` [PATCH 12/17] Add test-tree.c " David Malcolm
@ 2015-06-10 15:10 ` David Malcolm
  2015-06-10 15:17 ` [PATCH 03/17] Add test-cfg.c " David Malcolm
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-06-10 15:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/unittests/ChangeLog:
	* test-gimple.c: New file.
---
 gcc/unittests/test-gimple.c | 179 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 179 insertions(+)
 create mode 100644 gcc/unittests/test-gimple.c

diff --git a/gcc/unittests/test-gimple.c b/gcc/unittests/test-gimple.c
new file mode 100644
index 0000000..093f5fb
--- /dev/null
+++ b/gcc/unittests/test-gimple.c
@@ -0,0 +1,179 @@
+/* Unit tests for gimple.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 <gtest/gtest.h>
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "hard-reg-set.h"
+#include "input.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "gimple-expr.h"
+#include "toplev.h"
+#include "print-tree.h"
+#include "tree-iterator.h"
+#include "gimplify.h"
+#include "tree-cfg.h"
+#include "basic-block.h"
+#include "double-int.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "stmt.h"
+#include "hash-table.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "context.h"
+#include "hash-map.h"
+#include "plugin-api.h"
+#include "ipa-ref.h"
+#include "cgraph.h"
+#include "gimple-pretty-print.h"
+
+namespace {
+
+class gimple_test : public ::testing::Test
+{
+ protected:
+  void
+  verify_gimple_pp (const char *expected, gimple stmt)
+  {
+    pretty_printer pp;
+    pp_gimple_stmt_1 (&pp, stmt, 0 /* spc */, 0 /* flags */);
+    EXPECT_STREQ (expected, pp_formatted_text (&pp));
+  }
+};
+
+TEST_F (gimple_test, assign_single)
+{
+  /* Build "tmp = 5;"  */
+  tree type = integer_type_node;
+  tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			 get_identifier ("tmp"),
+			 type);
+  tree rhs = build_int_cst (type, 5);
+  gassign *stmt = gimple_build_assign (lhs, rhs);
+  verify_gimple_pp ("tmp = 5;", stmt);
+
+  EXPECT_TRUE (is_gimple_assign (stmt));
+  EXPECT_EQ (lhs, gimple_assign_lhs (stmt));
+  EXPECT_EQ (lhs, gimple_get_lhs (stmt));
+  EXPECT_EQ (rhs, gimple_assign_rhs1 (stmt));
+  EXPECT_EQ (NULL, gimple_assign_rhs2 (stmt));
+  EXPECT_EQ (NULL, gimple_assign_rhs3 (stmt));
+  EXPECT_TRUE (gimple_assign_single_p (stmt));
+  EXPECT_EQ (INTEGER_CST, gimple_assign_rhs_code (stmt));
+}
+
+TEST_F (gimple_test, assign_binop)
+{
+  /* Build "tmp = a + b;"  */
+  tree type = integer_type_node;
+  tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			 get_identifier ("tmp"),
+			 type);
+  tree a = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		       get_identifier ("a"),
+		       type);
+  tree b = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		       get_identifier ("b"),
+		       type);
+  gassign *stmt = gimple_build_assign (lhs, MULT_EXPR, a, b);
+  verify_gimple_pp ("tmp = a * b;", stmt);
+
+  EXPECT_TRUE (is_gimple_assign (stmt));
+  EXPECT_EQ (lhs, gimple_assign_lhs (stmt));
+  EXPECT_EQ (lhs, gimple_get_lhs (stmt));
+  EXPECT_EQ (a, gimple_assign_rhs1 (stmt));
+  EXPECT_EQ (b, gimple_assign_rhs2 (stmt));
+  EXPECT_EQ (NULL, gimple_assign_rhs3 (stmt));
+  EXPECT_FALSE (gimple_assign_single_p (stmt));
+  EXPECT_EQ (MULT_EXPR, gimple_assign_rhs_code (stmt));
+}
+
+TEST_F (gimple_test, nop_stmt)
+{
+  gimple stmt = gimple_build_nop ();
+  verify_gimple_pp ("GIMPLE_NOP", stmt);
+  EXPECT_EQ (GIMPLE_NOP, gimple_code (stmt));
+  EXPECT_EQ (NULL, gimple_get_lhs (stmt));
+  EXPECT_FALSE (gimple_assign_single_p (stmt));
+}
+
+TEST_F (gimple_test, return_stmt)
+{
+  /* Build "return 7;"  */
+  tree type = integer_type_node;
+  tree val = build_int_cst (type, 7);
+  greturn *stmt = gimple_build_return (val);
+  verify_gimple_pp ("return 7;", stmt);
+
+  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt));
+  EXPECT_EQ (NULL, gimple_get_lhs (stmt));
+  EXPECT_EQ (val, gimple_return_retval (stmt));
+  EXPECT_FALSE (gimple_assign_single_p (stmt));
+}
+
+TEST_F (gimple_test, return_without_value)
+{
+  greturn *stmt = gimple_build_return (NULL);
+  verify_gimple_pp ("return;", stmt);
+
+  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt));
+  EXPECT_EQ (NULL, gimple_get_lhs (stmt));
+  EXPECT_EQ (NULL, gimple_return_retval (stmt));
+  EXPECT_FALSE (gimple_assign_single_p (stmt));
+}
+
+}  /* anon namespace.  */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 08/17] Add test-hash-map.c to gcc/unittests
  2015-06-10 15:10 [PATCH 00/17] RFC: Addding a unit testing framework to gcc David Malcolm
                   ` (6 preceding siblings ...)
  2015-06-10 15:10 ` [PATCH 05/17] Add test-functions.c " David Malcolm
@ 2015-06-10 15:10 ` David Malcolm
  2015-06-10 15:10 ` [PATCH 12/17] Add test-tree.c " David Malcolm
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-06-10 15:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/unittests/ChangeLog:
	* test-hash-map.c: New file.
---
 gcc/unittests/test-hash-map.c | 78 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)
 create mode 100644 gcc/unittests/test-hash-map.c

diff --git a/gcc/unittests/test-hash-map.c b/gcc/unittests/test-hash-map.c
new file mode 100644
index 0000000..938c22b
--- /dev/null
+++ b/gcc/unittests/test-hash-map.c
@@ -0,0 +1,78 @@
+/* Unit tests for hash-map.h.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 <gtest/gtest.h>
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+
+namespace {
+
+TEST (hash_map_test, map_of_strings_to_int)
+{
+  hash_map <const char *, int> m;
+
+  const char *ostrich = "ostrich";
+  const char *elephant = "elephant";
+  const char *ant = "ant";
+  const char *spider = "spider";
+  const char *millipede = "Illacme plenipes";
+  const char *eric = "half a bee";
+
+  /* A fresh hash_map should be empty.  */
+  EXPECT_EQ (0, m.elements ());
+  EXPECT_EQ (NULL, m.get (ostrich));
+
+  /* Populate the hash_map.  */
+  EXPECT_EQ (false, m.put (ostrich, 2));
+  EXPECT_EQ (false, m.put (elephant, 4));
+  EXPECT_EQ (false, m.put (ant, 6));
+  EXPECT_EQ (false, m.put (spider, 8));
+  EXPECT_EQ (false, m.put (millipede, 750));
+  EXPECT_EQ (false, m.put (eric, 3));
+
+  /* Verify that we can recover the stored values.  */
+  EXPECT_EQ (6, m.elements ());
+  EXPECT_EQ (2, *m.get (ostrich));
+  EXPECT_EQ (4, *m.get (elephant));
+  EXPECT_EQ (6, *m.get (ant));
+  EXPECT_EQ (8, *m.get (spider));
+  EXPECT_EQ (750, *m.get (millipede));
+  EXPECT_EQ (3, *m.get (eric));
+
+  /* Verify removing an item.  */
+  m.remove (eric);
+  EXPECT_EQ (5, m.elements ());
+  EXPECT_EQ (NULL, m.get (eric));
+}
+
+}  /* anon namespace.  */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 05/17] Add test-functions.c to gcc/unittests
  2015-06-10 15:10 [PATCH 00/17] RFC: Addding a unit testing framework to gcc David Malcolm
                   ` (5 preceding siblings ...)
  2015-06-10 15:10 ` [PATCH 10/17] Add test-locations.c " David Malcolm
@ 2015-06-10 15:10 ` David Malcolm
  2015-06-10 15:10 ` [PATCH 08/17] Add test-hash-map.c " David Malcolm
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-06-10 15:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/unittests/ChangeLog:
	* test-functions.c: New file.
---
 gcc/unittests/test-functions.c | 634 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 634 insertions(+)
 create mode 100644 gcc/unittests/test-functions.c

diff --git a/gcc/unittests/test-functions.c b/gcc/unittests/test-functions.c
new file mode 100644
index 0000000..347e23f
--- /dev/null
+++ b/gcc/unittests/test-functions.c
@@ -0,0 +1,634 @@
+/* Unit tests for function-handling.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 <gtest/gtest.h>
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "hard-reg-set.h"
+#include "input.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "gimple-expr.h"
+#include "toplev.h"
+#include "print-tree.h"
+#include "tree-iterator.h"
+#include "gimplify.h"
+#include "tree-cfg.h"
+#include "basic-block.h"
+#include "double-int.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "stmt.h"
+#include "hash-table.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "context.h"
+#include "hash-map.h"
+#include "plugin-api.h"
+#include "ipa-ref.h"
+#include "cgraph.h"
+
+namespace {
+
+class function_test : public ::testing::Test
+{
+ protected:
+  tree
+  make_fndecl (tree return_type,
+	       const char *name,
+	       vec <tree> &param_types,
+	       bool is_variadic = false)
+  {
+    tree fn_type;
+    if (is_variadic)
+      fn_type = build_varargs_function_type_array (return_type,
+						   param_types.length (),
+						   param_types.address ());
+    else
+      fn_type = build_function_type_array (return_type,
+					   param_types.length (),
+					   param_types.address ());
+    /* FIXME: this uses input_location: */
+    tree fndecl = build_fn_decl (name, fn_type);
+
+    return fndecl;
+  }
+};
+
+TEST_F (function_test, fndecl_int_void)
+{
+  auto_vec <tree> param_types;
+  tree fndecl = make_fndecl (integer_type_node,
+			     "test_fndecl_int_void",
+			     param_types);
+  ASSERT_TRUE (fndecl != NULL);
+  if (0)
+    debug_tree (fndecl);
+
+  /* Verify name of decl.  */
+  tree declname = DECL_NAME (fndecl);
+  ASSERT_TRUE (declname != NULL);
+  EXPECT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
+  /* We expect it to use a *copy* of the string we passed in.  */
+  const char *identifier_ptr = IDENTIFIER_POINTER (declname);
+  EXPECT_NE ("test_fndecl_int_void", identifier_ptr);
+  EXPECT_EQ (0, strcmp ("test_fndecl_int_void", identifier_ptr));
+
+  /* Verify type of fndecl.  */
+  EXPECT_EQ (FUNCTION_DECL, TREE_CODE (fndecl));
+  tree fntype = TREE_TYPE (fndecl);
+  EXPECT_EQ (FUNCTION_TYPE, TREE_CODE (fntype));
+
+  /* Verify return type.  */
+  EXPECT_EQ (integer_type_node, TREE_TYPE (fntype));
+
+  /* Verify "void" args.  */
+  tree argtypes = TYPE_ARG_TYPES (fntype);
+  EXPECT_EQ (TREE_LIST, TREE_CODE (argtypes));
+  EXPECT_EQ (void_type_node, TREE_VALUE (argtypes));
+  EXPECT_EQ (NULL, TREE_CHAIN (argtypes));
+}
+
+TEST_F (function_test, fndecl_float_intchar)
+{
+  auto_vec <tree> param_types;
+  param_types.safe_push (integer_type_node);
+  param_types.safe_push (char_type_node);
+  tree fndecl = make_fndecl (float_type_node,
+			     "test_fndecl_float_intchar",
+			     param_types);
+  ASSERT_TRUE (fndecl != NULL);
+  if (0)
+    debug_tree (fndecl);
+
+  /* Verify name of decl.  */
+  tree declname = DECL_NAME (fndecl);
+  ASSERT_TRUE (declname != NULL);
+  EXPECT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
+  /* We expect it to use a *copy* of the string we passed in.  */
+  const char *identifier_ptr = IDENTIFIER_POINTER (declname);
+  EXPECT_NE ("test_fndecl_float_intchar", identifier_ptr);
+  EXPECT_EQ (0, strcmp ("test_fndecl_float_intchar", identifier_ptr));
+
+  /* Verify type of fndecl.  */
+  EXPECT_EQ (FUNCTION_DECL, TREE_CODE (fndecl));
+  tree fntype = TREE_TYPE (fndecl);
+  EXPECT_EQ (FUNCTION_TYPE, TREE_CODE (fntype));
+
+  /* Verify return type.  */
+  EXPECT_EQ (float_type_node, TREE_TYPE (fntype));
+
+  /* Verify "(int, char)" args.  */
+  tree arg0 = TYPE_ARG_TYPES (fntype);
+  EXPECT_EQ (TREE_LIST, TREE_CODE (arg0));
+  EXPECT_EQ (integer_type_node, TREE_VALUE (arg0));
+  tree arg1 = TREE_CHAIN (arg0);
+  ASSERT_TRUE (arg1 != NULL);
+  EXPECT_EQ (TREE_LIST, TREE_CODE (arg1));
+  EXPECT_EQ (char_type_node, TREE_VALUE (arg1));
+  tree argterm = TREE_CHAIN (arg1);
+  ASSERT_TRUE (argterm != NULL);
+  EXPECT_EQ (TREE_LIST, TREE_CODE (argterm));
+  EXPECT_EQ (void_type_node, TREE_VALUE (argterm));
+  EXPECT_EQ (NULL, TREE_CHAIN (argterm));
+}
+
+/* The test cases using this fixture take a trivial function:
+
+     int test_fn (void) { return 42; }
+
+   and test various conversions done to it:
+
+   - gimplification
+   - construction of the CFG
+   - conversion to SSA form
+   - expansion to RTL form
+
+   In avoid having one overlong test case, this is broken
+   up into separate test cases for each stage, with helper methods
+   in this fixture to minimize code duplication.
+
+   Another approach would be to attempt to directly construct a function
+   in the appropriate representation at each stage, though presumably
+   that would exhibit different kinds of failure compared to this
+   approach.  */
+
+class representation_test : public function_test
+{
+ protected:
+  /* Construct this function:
+       int test_fn (void) { return 42; }
+     in generic tree form.  Return the fndecl.  */
+  tree
+  build_trivial_generic_function ()
+  {
+    auto_vec <tree> param_types;
+    tree fndecl = make_fndecl (integer_type_node,
+			       "test_fn",
+			       param_types);
+    EXPECT_TRUE (fndecl != NULL);
+
+    /* Populate the function.  */
+    tree retval = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+			      NULL_TREE, integer_type_node);
+    DECL_ARTIFICIAL (retval) = 1;
+    DECL_IGNORED_P (retval) = 1;
+    DECL_RESULT (fndecl) = retval;
+
+    /* Create a BIND_EXPR, and within it, a statement list.  */
+    tree stmt_list = alloc_stmt_list ();
+    tree_stmt_iterator stmt_iter = tsi_start (stmt_list);
+    tree block = make_node (BLOCK);
+    tree bind_expr =
+      build3 (BIND_EXPR, void_type_node, NULL, stmt_list, block);
+
+    tree modify_retval = build2 (MODIFY_EXPR,
+				 integer_type_node,
+				 retval,
+				 build_int_cst (integer_type_node, 42));
+    tree return_stmt = build1 (RETURN_EXPR,
+			       integer_type_node,
+			       modify_retval);
+    tsi_link_after (&stmt_iter, return_stmt, TSI_CONTINUE_LINKING);
+
+    DECL_INITIAL (fndecl) = block;
+
+    /* how to add to function? the following appears to be how to
+       set the body of a fndecl: */
+    DECL_SAVED_TREE(fndecl) = bind_expr;
+
+    /* Ensure that locals appear in the debuginfo.  */
+    BLOCK_VARS (block) = BIND_EXPR_VARS (bind_expr);
+
+    if (0)
+      debug_tree (fndecl);
+
+    return fndecl;
+  }
+
+  /* Construct this function:
+       int test_fn (void) { return 42; }
+     in "high gimple" form.  Return the fndecl.  */
+  tree
+  build_trivial_high_gimple_function ()
+  {
+    /* Construct a trivial function, and gimplify it: */
+    tree fndecl = build_trivial_generic_function ();
+    gimplify_function_tree (fndecl);
+    return fndecl;
+  }
+
+  /* Build a CFG for a function in gimple form.  */
+  void
+  build_cfg (tree fndecl)
+  {
+    function *fun = DECL_STRUCT_FUNCTION (fndecl);
+    ASSERT_TRUE (fun != NULL);
+    EXPECT_EQ (fndecl, fun->decl);
+
+    /* We first have to lower control flow; for our trivial test function
+       this gives us:
+	 test_fn ()
+	 {
+	   D.56 = 42;
+	   goto <D.57>;
+	   <D.57>:
+	   return D.56;
+	 }
+    */
+    gimple_opt_pass *lower_cf_pass = make_pass_lower_cf (g);
+    push_cfun (fun);
+    lower_cf_pass->execute (fun);
+    pop_cfun ();
+    if (0)
+      dump_function_to_file (fndecl, stderr, 0);
+
+    /* We can now convert to CFG form; for our trivial test function this
+       gives us:
+	 test_fn ()
+	 {
+	   <bb 2>:
+	   D.56 = 42;
+	   return D.56;
+	 }
+    */
+    gimple_opt_pass *build_cfg_pass = make_pass_build_cfg (g);
+    push_cfun (fun);
+    build_cfg_pass->execute (fun);
+    pop_cfun ();
+    if (0)
+      dump_function_to_file (fndecl, stderr, 0);
+  }
+
+  /* Convert a gimple+CFG function to SSA form.  */
+  void
+  convert_to_ssa (tree fndecl)
+  {
+    function *fun = DECL_STRUCT_FUNCTION (fndecl);
+    ASSERT_TRUE (fun != NULL);
+    EXPECT_EQ (fndecl, fun->decl);
+
+    gimple_opt_pass *pass_init_datastructures =
+      make_pass_init_datastructures (g);
+    gimple_opt_pass *build_ssa_pass = make_pass_build_ssa (g);
+    push_cfun (fun);
+    pass_init_datastructures->execute (fun);
+    build_ssa_pass->execute (fun);
+    pop_cfun ();
+  }
+
+  /* Assuming we have a simple 3-block CFG like this:
+       [ENTRY] -> [block2] -> [EXIT]
+     get the "real" basic block (block 2).  */
+  basic_block
+  get_real_block (function *fun)
+  {
+    EXPECT_TRUE (fun->cfg != NULL);
+    EXPECT_EQ (3, n_basic_blocks_for_fn (fun));
+    basic_block bb2 = (*fun->cfg->x_basic_block_info)[2];
+    EXPECT_TRUE (bb2 != NULL);
+    return bb2;
+  }
+
+  /* Verify that we have a simple 3-block CFG: the two "fake" ones, and
+     a "real" one:
+     [ENTRY] -> [block2] -> [EXIT].  */
+  void
+  verify_three_block_cfg (function *fun)
+  {
+    ASSERT_TRUE (fun->cfg != NULL);
+    EXPECT_EQ (3, n_basic_blocks_for_fn (fun));
+    EXPECT_EQ (2, n_edges_for_fn (fun));
+
+    /* The "fake" basic blocks.  */
+    basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (entry != NULL);
+    EXPECT_EQ (ENTRY_BLOCK, entry->index);
+
+    basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (exit != NULL);
+    EXPECT_EQ (EXIT_BLOCK, exit->index);
+
+    /* The "real" basic block.  */
+    basic_block bb2 = get_real_block (fun);
+    ASSERT_TRUE (bb2 != NULL);
+    EXPECT_EQ (2, bb2->index);
+
+    /* Verify connectivity.  */
+    EXPECT_EQ (NULL, entry->preds);
+    EXPECT_EQ (1, entry->succs->length ());
+
+    edge from_entry_to_bb2 = (*entry->succs)[0];
+    EXPECT_EQ (entry, from_entry_to_bb2->src);
+    EXPECT_EQ (bb2, from_entry_to_bb2->dest);
+
+    EXPECT_EQ (1, bb2->preds->length ());
+    EXPECT_EQ (from_entry_to_bb2, (*bb2->preds)[0]);
+    EXPECT_EQ (1, bb2->succs->length ());
+
+    edge from_bb2_to_exit = (*bb2->succs)[0];
+    EXPECT_EQ (bb2, from_bb2_to_exit->src);
+    EXPECT_EQ (exit, from_bb2_to_exit->dest);
+
+    EXPECT_EQ (1, exit->preds->length ());
+    EXPECT_EQ (from_bb2_to_exit, (*exit->preds)[0]);
+    EXPECT_EQ (NULL, exit->succs);
+  }
+
+  /* As above, but additionally verify the gimple statements are sane.  */
+  void
+  verify_three_block_gimple_cfg (function *fun)
+  {
+    verify_three_block_cfg (fun);
+
+    /* The "fake" basic blocks should be flagged as gimple, but with have no
+       statements.  */
+    basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (entry != NULL);
+    EXPECT_EQ (0, entry->flags & BB_RTL);
+    EXPECT_EQ (NULL, bb_seq (entry));
+
+    basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (exit != NULL);
+    EXPECT_EQ (0, entry->flags & BB_RTL);
+    EXPECT_EQ (NULL, bb_seq (exit));
+
+    /* The "real" basic block should be flagged as gimple, and have one
+       or more statements.  */
+    basic_block bb2 = get_real_block (fun);
+    ASSERT_TRUE (bb2 != NULL);
+    EXPECT_EQ (0, entry->flags & BB_RTL);
+    EXPECT_TRUE (bb_seq (bb2) != NULL);
+  }
+
+  /* As above, but additionally verify the RTL insns are sane.  */
+  void
+  verify_three_block_rtl_cfg (function *fun)
+  {
+    verify_three_block_cfg (fun);
+
+    /* The "fake" basic blocks should be flagged as RTL, but with no
+       insns.  */
+    basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (entry != NULL);
+    EXPECT_EQ (BB_RTL, entry->flags & BB_RTL);
+    EXPECT_EQ (NULL, BB_HEAD (entry));
+
+    basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (exit != NULL);
+    EXPECT_EQ (BB_RTL, entry->flags & BB_RTL);
+    EXPECT_EQ (NULL, BB_HEAD (exit));
+
+    /* The "real" basic block should be flagged as RTL, and have one
+       or more insns.  */
+    basic_block bb2 = get_real_block (fun);
+    ASSERT_TRUE (bb2 != NULL);
+    EXPECT_EQ (BB_RTL, entry->flags & BB_RTL);
+    EXPECT_TRUE (BB_HEAD (bb2) != NULL);
+  }
+
+};
+
+/* Test converting our trivial function:
+     int test_fn (void) { return 42; }
+   to gimple form.  */
+
+TEST_F (representation_test, gimplification)
+{
+  tree fndecl = build_trivial_generic_function ();
+
+  /* Convert to gimple: */
+  gimplify_function_tree (fndecl);
+
+  if (0)
+    dump_function_to_file (fndecl, stderr, 0);
+
+  /* Verify that we got gimple out of it.  */
+
+  /* The function is now in GIMPLE form but the CFG has not been
+     built yet.  */
+
+  /* We should have a struct function for the decl.  */
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  EXPECT_EQ (fndecl, fun->decl);
+
+  /* We expect a GIMPLE_BIND, with two gimple statements within it:
+       tmp = 42;
+       return tmp;  */
+
+  gimple_seq seq_fn_body = gimple_body (fndecl);
+  EXPECT_TRUE (seq_fn_body != NULL);
+  gimple bind_stmt = gimple_seq_first_stmt (seq_fn_body);
+  EXPECT_EQ (GIMPLE_BIND, gimple_code (bind_stmt));
+  EXPECT_EQ (NULL, bind_stmt->next);
+
+  gimple_seq seq_bind_body = gimple_bind_body (as_a <gbind *> (bind_stmt));
+
+  /* Verify that we have the 2 statements we expect.  */
+  EXPECT_TRUE (seq_bind_body != NULL);
+  gimple stmt1 = gimple_seq_first_stmt (seq_bind_body);
+  ASSERT_TRUE (stmt1 != NULL);
+  EXPECT_EQ (GIMPLE_ASSIGN, gimple_code (stmt1));
+  gimple stmt2 = stmt1->next;
+  ASSERT_TRUE (stmt2 != NULL);
+  EXPECT_EQ (stmt1, stmt2->prev);
+  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt2));
+}
+
+/* Test of building a CFG for a function in high gimple form.  */
+
+TEST_F (representation_test, building_cfg)
+{
+  /* Construct a trivial function, and gimplify it: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+
+  /* Build a CFG.  */
+  build_cfg (fndecl);
+
+  /* We should now have a simple 3-block cfg: the two "fake" ones, and
+     a "real" one:
+       [ENTRY] -> [block2] -> [EXIT].  */
+  verify_three_block_gimple_cfg (fun);
+
+  /* Verify the statements within the "real" block; we expect somehing
+     like this:
+	 test_fn ()
+	 {
+	   <bb 2>:
+	   D.56 = 42;
+	   return D.56;
+	 }
+  */
+  basic_block bb2 = get_real_block (fun);
+  gimple stmt_a = gimple_seq_first_stmt (bb_seq (bb2));
+  EXPECT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a));
+  gimple stmt_b = stmt_a->next;
+  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt_b));
+  EXPECT_EQ (NULL, stmt_b->next);
+}
+
+/* Test of conversion of gimple to SSA form.  */
+TEST_F (representation_test, conversion_to_ssa)
+{
+  /* As above, construct a trivial function, gimplify it, and build a CFG: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  build_cfg (fndecl);
+
+  convert_to_ssa (fndecl);
+
+  verify_three_block_gimple_cfg (fun);
+
+  /* For out trivial test function we should now have something like
+     this:
+       test_fn ()
+       {
+	 <bb 2>:
+	 _1 = 42;
+	 return _1;
+       }
+  */
+  if (0)
+    dump_function_to_file (fndecl, stderr, 0);
+  basic_block bb2 = get_real_block (fun);
+  gimple stmt_a = gimple_seq_first_stmt (bb_seq (bb2));
+  EXPECT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a));
+
+  gimple stmt_b = stmt_a->next;
+  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt_b));
+  EXPECT_EQ (NULL, stmt_b->next);
+
+  greturn *return_stmt = as_a <greturn *> (stmt_b);
+  EXPECT_EQ (SSA_NAME, TREE_CODE (gimple_return_retval (return_stmt)));
+}
+
+/* Test of expansion from gimple-ssa to RTL.  */
+
+TEST_F (representation_test, expansion_to_rtl)
+{
+  /* As above, construct a trivial function, gimplify it, build a CFG,
+     and convert to SSA: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  build_cfg (fndecl);
+  convert_to_ssa (fndecl);
+
+  /* We need a cgraph_node for it.  */
+  cgraph_node::get_create (fndecl);
+  /* Normally, cgraph_node::expand () would call
+     init_function_start (and a bunch of other stuff),
+     and invoke the expand pass, but it also runs
+     all of the other passes.  So just do the minimum
+     needed to get from gimple-SSA to RTL.  */
+  rtl_opt_pass *expand_pass = make_pass_expand (g);
+  push_cfun (fun);
+  init_function_start (fndecl);
+  expand_pass->execute (fun);
+  pop_cfun ();
+
+  /* On x86_64, I get this:
+       (note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+       (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
+       (insn 5 2 6 2 (set (reg:SI 87 [ D.59 ])
+			  (const_int 42 [0x2a])) -1 (nil))
+       (insn 6 5 10 2 (set (reg:SI 88 [ <retval> ])
+			   (reg:SI 87 [ D.59 ])) -1 (nil))
+       (insn 10 6 11 2 (set (reg/i:SI 0 ax)
+			    (reg:SI 88 [ <retval> ])) -1 (nil))
+       (insn 11 10 0 2 (use (reg/i:SI 0 ax)) -1 (nil))
+   */
+  if (0)
+    dump_function_to_file (fndecl, stderr, 0);
+
+  verify_three_block_rtl_cfg (fun);
+
+  /* Verify as much of the RTL as we can whilst avoiding
+     target-specific behavior.  */
+  basic_block bb2 = get_real_block (fun);
+
+  /* Expect a NOTE_INSN_BASIC_BLOCK... */
+  rtx_insn *insn = BB_HEAD (bb2);
+  ASSERT_TRUE (insn != NULL);
+  EXPECT_EQ (NOTE, insn->code);
+  EXPECT_EQ (NOTE_INSN_BASIC_BLOCK, NOTE_KIND (insn));
+  EXPECT_EQ (bb2, NOTE_BASIC_BLOCK (insn));
+
+  /* ...followed by a NOTE_INSN_FUNCTION_BEG...  */
+  insn = NEXT_INSN (insn);
+  ASSERT_TRUE (insn != NULL);
+  EXPECT_EQ (NOTE, insn->code);
+  EXPECT_EQ (NOTE_INSN_FUNCTION_BEG, NOTE_KIND (insn));
+
+  /* ...followed by a SET of a reg to the const value.  */
+  insn = NEXT_INSN (insn);
+  ASSERT_TRUE (insn != NULL);
+  EXPECT_EQ (INSN, insn->code);
+  rtx pat = PATTERN (insn);
+  ASSERT_TRUE (pat != NULL);
+  EXPECT_EQ (SET, pat->code);
+  EXPECT_EQ (REG, SET_DEST (pat)->code);
+  EXPECT_EQ (CONST_INT, SET_SRC (pat)->code);
+  EXPECT_EQ (42, INTVAL (SET_SRC (pat)));
+
+  /* ...etc; any further checks are likely to over-specify things
+     and run us into target dependencies.  */
+}
+
+}  // anon namespace
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 11/17] Add test-rtl.c to gcc/unittests
  2015-06-10 15:10 [PATCH 00/17] RFC: Addding a unit testing framework to gcc David Malcolm
                   ` (2 preceding siblings ...)
  2015-06-10 15:10 ` [PATCH 02/17] Add test-bitmap.c " David Malcolm
@ 2015-06-10 15:10 ` David Malcolm
  2015-06-10 15:10 ` [PATCH 04/17] Add test-folding.c " David Malcolm
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-06-10 15:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/unittests/ChangeLog:
	* test-rtl.c: New file.
---
 gcc/unittests/test-rtl.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 94 insertions(+)
 create mode 100644 gcc/unittests/test-rtl.c

diff --git a/gcc/unittests/test-rtl.c b/gcc/unittests/test-rtl.c
new file mode 100644
index 0000000..cba7bb8
--- /dev/null
+++ b/gcc/unittests/test-rtl.c
@@ -0,0 +1,94 @@
+/* Unit tests for RTL-handling.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 <gtest/gtest.h>
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "pretty-print.h"
+#include "cfgbuild.h"
+
+namespace {
+
+class rtl_test : public ::testing::Test
+{
+ protected:
+  void
+  verify_print_pattern (const char *expected, rtx pat)
+  {
+    pretty_printer pp;
+    print_pattern (&pp, pat, 1);
+    EXPECT_STREQ (expected, pp_formatted_text (&pp));
+  }
+};
+
+/* Unit testing of "single_set".  */
+TEST_F (rtl_test, test_single_set)
+{
+  /* A label is not a SET.  */
+  EXPECT_EQ (NULL_RTX, single_set (gen_label_rtx ()));
+
+  /* An unconditional jump insn is a single SET.  */
+  rtx set_pc = gen_rtx_SET (pc_rtx,
+			    gen_rtx_LABEL_REF (VOIDmode,
+					       gen_label_rtx ()));
+  rtx_insn *jump_insn = emit_jump_insn (set_pc);
+  EXPECT_EQ (set_pc, single_set (jump_insn));
+
+  /* etc */
+}
+
+TEST_F (rtl_test, uncond_jump)
+{
+  rtx_insn *label = gen_label_rtx ();
+  rtx jump_pat = gen_rtx_SET (pc_rtx,
+			      gen_rtx_LABEL_REF (VOIDmode,
+						 label));
+  EXPECT_EQ (SET, jump_pat->code);
+  EXPECT_EQ (LABEL_REF, SET_SRC (jump_pat)->code);
+  EXPECT_EQ (label, LABEL_REF_LABEL (SET_SRC (jump_pat)));
+  EXPECT_EQ (PC, SET_DEST (jump_pat)->code);
+
+  verify_print_pattern ("pc=L0", jump_pat);
+
+  rtx_insn *jump_insn = emit_jump_insn (jump_pat);
+  EXPECT_FALSE (any_condjump_p (jump_insn));
+  EXPECT_TRUE (any_uncondjump_p (jump_insn));
+  EXPECT_TRUE (pc_set (jump_insn));
+  EXPECT_TRUE (simplejump_p (jump_insn));
+  EXPECT_TRUE (onlyjump_p (jump_insn));
+  EXPECT_TRUE (control_flow_insn_p (jump_insn));
+}
+
+}  /* anon namespace.  */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 01/17] Add Make-lang.in and config-lang.in to gcc/unittests
  2015-06-10 15:10 [PATCH 00/17] RFC: Addding a unit testing framework to gcc David Malcolm
  2015-06-10 15:10 ` [PATCH 09/17] Add test-hash-set.c to gcc/unittests David Malcolm
@ 2015-06-10 15:10 ` David Malcolm
  2015-06-10 15:10 ` [PATCH 02/17] Add test-bitmap.c " David Malcolm
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-06-10 15:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/unittests/ChangeLog:
	* Make-lang.in: New file.
	* config-lang.in: New file.
---
 gcc/unittests/Make-lang.in   | 200 +++++++++++++++++++++++++++++++++++++++++++
 gcc/unittests/config-lang.in |  34 ++++++++
 2 files changed, 234 insertions(+)
 create mode 100644 gcc/unittests/Make-lang.in
 create mode 100644 gcc/unittests/config-lang.in

diff --git a/gcc/unittests/Make-lang.in b/gcc/unittests/Make-lang.in
new file mode 100644
index 0000000..50d6e4f
--- /dev/null
+++ b/gcc/unittests/Make-lang.in
@@ -0,0 +1,200 @@
+# Top level -*- makefile -*- fragment for unittests.
+#   Copyright (C) 2013-2015 Free Software Foundation, Inc.
+
+#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/>.
+
+# This file provides the language dependent support in the main Makefile.
+# Each language makefile fragment must provide the following targets:
+#
+# foo.all.cross, foo.start.encap, foo.rest.encap,
+# foo.install-common, foo.install-man, foo.install-info, foo.install-pdf,
+# foo.install-html, foo.info, foo.dvi, foo.pdf, foo.html, foo.uninstall,
+# foo.mostlyclean, foo.clean, foo.distclean,
+# foo.maintainer-clean, foo.stage1, foo.stage2, foo.stage3, foo.stage4
+#
+# where `foo' is the name of the language.
+#
+# It should also provide rules for:
+#
+# - making any compiler driver (eg: g++)
+# - the compiler proper (eg: cc1plus)
+# - define the names for selecting the language in LANGUAGES.
+
+#\f
+# Define the names for selecting unittests in LANGUAGES.
+# Note that it would be nice to move the dependency on g++
+# into the unittests rule, but that needs a little bit of work
+# to do the right thing within all.cross.
+
+LIBGCCUNITTESTS_LINKER_NAME = libgccunittests.so
+LIBGCCUNITTESTS_VERSION_NUM = 0
+LIBGCCUNITTESTS_MINOR_NUM = 0
+LIBGCCUNITTESTS_RELEASE_NUM = 1
+LIBGCCUNITTESTS_SONAME = $(LIBGCCUNITTESTS_LINKER_NAME).$(LIBGCCUNITTESTS_VERSION_NUM)
+LIBGCCUNITTESTS_FILENAME = \
+  $(LIBGCCUNITTESTS_SONAME).$(LIBGCCUNITTESTS_MINOR_NUM).$(LIBGCCUNITTESTS_RELEASE_NUM)
+
+LIBGCCUNITTESTS_LINKER_NAME_SYMLINK = $(LIBGCCUNITTESTS_LINKER_NAME)
+LIBGCCUNITTESTS_SONAME_SYMLINK = $(LIBGCCUNITTESTS_SONAME)
+
+TESTPROGRAMS = unittests.exe
+
+RUN_TESTPROGRAMS = run-unittests.exe
+
+unittests: $(LIBGCCUNITTESTS_FILENAME) \
+	$(LIBGCCUNITTESTS_SYMLINK) \
+	$(LIBGCCUNITTESTS_LINKER_NAME_SYMLINK) \
+	$(FULL_DRIVER_NAME) \
+	$(TESTPROGRAMS) \
+	$(RUN_TESTPROGRAMS)
+
+# Tell GNU make to ignore these if they exist.
+.PHONY: unittests $(RUN_TESTPROGRAMS)
+
+# "Frontend" objects, which go into libgccunittests.so
+unittests_OBJS = attribs.o \
+	unittests/unittests-frontend.o
+
+# Build various files against gtest
+
+# Files that are linked into unittests.exe
+UNITTESTS_EXE_OBJS = \
+	test-bitmap.o \
+	test-cfg.o \
+	test-folding.o \
+	test-functions.o \
+	test-gimple.o \
+	test-hash-map.o \
+	test-hash-set.o \
+	test-locations.o \
+	test-rtl.o \
+	test-tree.o \
+	test-vec.o \
+	test-wide-int.o \
+	unittests-main.o
+
+# Files to be built against gtest
+# test-ggc.o has to be linked in to libgccunittests.so
+OBJS_BUILT_AGAINST_GTEST = $(UNITTESTS_EXE_OBJS) test-ggc.o
+
+# All objects (for the main Makefile.in's dependency tracking)
+#extra_OBJS += $(OBJS_BUILT_AGAINST_GTEST)
+
+# Use strict warnings for this front end.
+unittests-warn = $(STRICT_WARN)
+
+# We avoid using $(BACKEND) from Makefile.in in order to avoid pulling
+# in main.o
+$(LIBGCCUNITTESTS_FILENAME): $(unittests_OBJS) \
+	libbackend.a libcommon-target.a libcommon.a \
+	$(CPPLIB) $(LIBDECNUMBER) \
+	$(LIBDEPS) test-ggc.o
+	+$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ -shared \
+	     $(unittests_OBJS) libbackend.a libcommon-target.a libcommon.a \
+	     $(CPPLIB) $(LIBDECNUMBER) $(LIBS) $(BACKENDLIBS) test-ggc.o \
+	     -Wl,-soname,$(LIBGCCUNITTESTS_SONAME)
+
+$(LIBGCCUNITTESTS_SONAME_SYMLINK): $(LIBGCCUNITTESTS_FILENAME)
+	ln -sf $(LIBGCCUNITTESTS_FILENAME) $(LIBGCCUNITTESTS_SONAME_SYMLINK)
+
+$(LIBGCCUNITTESTS_LINKER_NAME_SYMLINK): $(LIBGCCUNITTESTS_SONAME_SYMLINK)
+	ln -sf $(LIBGCCUNITTESTS_SONAME_SYMLINK) $(LIBGCCUNITTESTS_LINKER_NAME_SYMLINK)
+
+#\f
+# Build hooks:
+
+unittests.all.cross:
+unittests.start.encap:
+unittests.rest.encap:
+
+$(OBJS_BUILT_AGAINST_GTEST): %.o: $(srcdir)/unittests/%.c
+	$(COMPILER) \
+	  $(shell gtest-config --cppflags --cxxflags) \
+	  $(INCLUDES) \
+	  $(ALL_COMPILERFLAGS) \
+	  -c -o $@ $<
+
+unittests.exe: $(UNITTESTS_EXE_OBJS) $(LIBGCCUNITTESTS_LINKER_NAME_SYMLINK)
+	$(LINKER) \
+	  $(shell gtest-config --ldflags --libs) \
+	  $(ALL_LINKERFLAGS) \
+	  -L. -lgccunittests \
+	  -o $@ \
+	  $(UNITTESTS_EXE_OBJS) \
+	  $(LIBGCCUNITTESTS_LINKER_NAME_SYMLINK)
+
+run-unittests.exe: unittests.exe
+	LD_LIBRARY_PATH=. ./unittests.exe
+
+# Documentation build hooks.
+unittests.info:
+unittests.man:
+
+# Testing hooks:
+lang_checks += check-unittests
+
+#\f
+# Install hooks:
+unittests.install-common: installdirs
+	$(INSTALL_PROGRAM) $(LIBGCCUNITTESTS_FILENAME) \
+	  $(DESTDIR)/$(libdir)/$(LIBGCCUNITTESTS_FILENAME)
+	ln -sf \
+	  $(LIBGCCUNITTESTS_FILENAME) \
+	  $(DESTDIR)/$(libdir)/$(LIBGCCUNITTESTS_SONAME_SYMLINK)
+	ln -sf \
+	  $(LIBGCCUNITTESTS_SONAME_SYMLINK)\
+	  $(DESTDIR)/$(libdir)/$(LIBGCCUNITTESTS_LINKER_NAME_SYMLINK)
+	$(INSTALL_PROGRAM) $(srcdir)/unittests/libgccunittests.h \
+	  $(DESTDIR)/$(includedir)/libgccunittests.h
+	$(INSTALL_PROGRAM) $(srcdir)/unittests/libgccunittests++.h \
+	  $(DESTDIR)/$(includedir)/libgccunittests++.h
+
+unittests.install-man:
+
+unittests.install-plugin:
+
+unittests.uninstall:
+
+#\f
+# Clean hooks:
+# A lot of the ancillary files are deleted by the main makefile.
+# We just have to delete files specific to us.
+
+unittests.mostlyclean:
+
+unittests.clean:
+
+unittests.distclean:
+
+unittests.maintainer-clean:
+
+#\f
+# Stage hooks:
+# The main makefile has already created stage?/unittests.
+
+unittests.stage1: stage1-start
+	-mv unittests/*$(objext) stage1/unittests
+unittests.stage2: stage2-start
+	-mv unittests/*$(objext) stage2/unittests
+unittests.stage3: stage3-start
+	-mv unittests/*$(objext) stage3/unittests
+unittests.stage4: stage4-start
+	-mv unittests/*$(objext) stage4/unittests
+unittests.stageprofile: stageprofile-start
+	-mv unittests/*$(objext) stageprofile/unittests
+unittests.stagefeedback: stagefeedback-start
+	-mv unittests/*$(objext) stagefeedback/unittests
diff --git a/gcc/unittests/config-lang.in b/gcc/unittests/config-lang.in
new file mode 100644
index 0000000..1e0bfd7
--- /dev/null
+++ b/gcc/unittests/config-lang.in
@@ -0,0 +1,34 @@
+# Top level configure fragment for unittests
+#   Copyright (C) 2013-2015 Free Software Foundation, Inc.
+
+#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/>.
+
+# Configure looks for the existence of this file to auto-config each language.
+# We define several parameters used by configure:
+#
+# language	- name of language as it would appear in $(LANGUAGES)
+# compilers	- value to add to $(COMPILERS)
+
+language="unittests"
+
+compilers="unittest-suite"
+
+target_libs=""
+
+gtfiles="\$(srcdir)/unittests/unittests-frontend.c \$(srcdir)/unittests/test-ggc.c"
+
+build_by_default="no"
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 12/17] Add test-tree.c to gcc/unittests
  2015-06-10 15:10 [PATCH 00/17] RFC: Addding a unit testing framework to gcc David Malcolm
                   ` (7 preceding siblings ...)
  2015-06-10 15:10 ` [PATCH 08/17] Add test-hash-map.c " David Malcolm
@ 2015-06-10 15:10 ` David Malcolm
  2015-06-10 15:10 ` [PATCH 07/17] Add test-gimple.c " David Malcolm
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-06-10 15:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/unittests/ChangeLog:
	* test-tree.c: New file.
---
 gcc/unittests/test-tree.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 102 insertions(+)
 create mode 100644 gcc/unittests/test-tree.c

diff --git a/gcc/unittests/test-tree.c b/gcc/unittests/test-tree.c
new file mode 100644
index 0000000..d6832d2
--- /dev/null
+++ b/gcc/unittests/test-tree.c
@@ -0,0 +1,102 @@
+/* Unit tests for GCC's tree types.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 <gtest/gtest.h>
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "hard-reg-set.h"
+#include "input.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "gimple-expr.h"
+#include "toplev.h"
+#include "print-tree.h"
+#include "tree-iterator.h"
+#include "gimplify.h"
+#include "tree-cfg.h"
+#include "fold-const.h"
+
+namespace {
+
+/* Verify that integer constants are sane.  */
+
+TEST (tree_test, integer_constants)
+{
+  ASSERT_TRUE (integer_type_node != NULL);
+  EXPECT_TRUE (build_int_cst (integer_type_node, 0) != NULL);
+
+  tree type = integer_type_node;
+
+  tree zero = build_zero_cst (type);
+  EXPECT_EQ (INTEGER_CST, TREE_CODE (zero));
+  EXPECT_EQ (type, TREE_TYPE (zero));
+
+  tree one = build_int_cst (type, 1);
+  EXPECT_EQ (INTEGER_CST, TREE_CODE (one));
+  EXPECT_EQ (type, TREE_TYPE (zero));
+}
+
+/* Verify identifiers.  */
+
+TEST (tree_test, identifiers)
+{
+  tree identifier = get_identifier ("foo");
+  EXPECT_EQ (3, IDENTIFIER_LENGTH (identifier));
+  EXPECT_STREQ ("foo", IDENTIFIER_POINTER (identifier));
+}
+
+/* Verify LABEL_DECL.  */
+
+TEST (tree_test, labels)
+{
+  tree identifier = get_identifier ("err");
+  tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
+				identifier, void_type_node);
+  EXPECT_EQ (-1, LABEL_DECL_UID (label_decl));
+  EXPECT_FALSE (FORCED_LABEL (label_decl));
+}
+
+}  // anon namespace
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 02/17] Add test-bitmap.c to gcc/unittests
  2015-06-10 15:10 [PATCH 00/17] RFC: Addding a unit testing framework to gcc David Malcolm
  2015-06-10 15:10 ` [PATCH 09/17] Add test-hash-set.c to gcc/unittests David Malcolm
  2015-06-10 15:10 ` [PATCH 01/17] Add Make-lang.in and config-lang.in " David Malcolm
@ 2015-06-10 15:10 ` David Malcolm
  2015-06-23 19:17   ` Jeff Law
  2015-06-10 15:10 ` [PATCH 11/17] Add test-rtl.c " David Malcolm
                   ` (15 subsequent siblings)
  18 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-06-10 15:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/unittests/ChangeLog:
	* test-bitmap.c: New file.
---
 gcc/unittests/test-bitmap.c | 117 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 117 insertions(+)
 create mode 100644 gcc/unittests/test-bitmap.c

diff --git a/gcc/unittests/test-bitmap.c b/gcc/unittests/test-bitmap.c
new file mode 100644
index 0000000..38adff3
--- /dev/null
+++ b/gcc/unittests/test-bitmap.c
@@ -0,0 +1,117 @@
+/* Unit tests for GCC's bitmap-handling.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 <gtest/gtest.h>
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "bitmap.h"
+
+namespace {
+
+/* Freshly-created bitmaps ought to be empty.  */
+
+TEST (bitmap_test, gc_alloc)
+{
+  bitmap b = bitmap_gc_alloc ();
+  EXPECT_TRUE (bitmap_empty_p (b));
+}
+
+/* Verify bitmap_set_range.  */
+
+TEST (bitmap_test, set_range)
+{
+  bitmap b = bitmap_gc_alloc ();
+  EXPECT_TRUE (bitmap_empty_p (b));
+
+  bitmap_set_range (b, 7, 5);
+  EXPECT_FALSE (bitmap_empty_p (b));
+  EXPECT_EQ (5, bitmap_count_bits (b));
+
+  /* Verify bitmap_bit_p at the boundaries.  */
+  EXPECT_FALSE (bitmap_bit_p (b, 6));
+  EXPECT_TRUE (bitmap_bit_p (b, 7));
+  EXPECT_TRUE (bitmap_bit_p (b, 11));
+  EXPECT_FALSE (bitmap_bit_p (b, 12));
+}
+
+/* Verify splitting a range into two pieces using bitmap_clear_bit.  */
+
+TEST (bitmap_test, clear_bit_in_middle)
+{
+  bitmap b = bitmap_gc_alloc ();
+
+  /* Set b to [100..200].  */
+  bitmap_set_range (b, 100, 100);
+  EXPECT_EQ (100, bitmap_count_bits (b));
+
+  /* Clear a bit in the middle.  */
+  bool changed = bitmap_clear_bit (b, 150);
+  EXPECT_TRUE (changed);
+  EXPECT_EQ (99, bitmap_count_bits (b));
+  EXPECT_TRUE (bitmap_bit_p (b, 149));
+  EXPECT_FALSE (bitmap_bit_p (b, 150));
+  EXPECT_TRUE (bitmap_bit_p (b, 151));
+}
+
+/* Verify bitmap_copy.  */
+
+TEST (bitmap_test, copying)
+{
+  bitmap src = bitmap_gc_alloc ();
+  bitmap_set_range (src, 40, 10);
+
+  bitmap dst = bitmap_gc_alloc ();
+  EXPECT_FALSE (bitmap_equal_p (src, dst));
+  bitmap_copy (dst, src);
+  EXPECT_TRUE (bitmap_equal_p (src, dst));
+
+  /* Verify that we can make them unequal again...  */
+  bitmap_set_range (src, 70, 5);
+  EXPECT_FALSE (bitmap_equal_p (src, dst));
+
+  /* ...and that changing src after the copy didn't affect
+     the other: */
+  EXPECT_FALSE (bitmap_bit_p (dst, 70));
+}
+
+/* Verify bitmap_single_bit_set_p.  */
+TEST (bitmap_test, bitmap_single_bit_set_p)
+{
+  bitmap b = bitmap_gc_alloc ();
+
+  EXPECT_FALSE (bitmap_single_bit_set_p (b));
+
+  bitmap_set_range (b, 42, 1);
+  EXPECT_TRUE (bitmap_single_bit_set_p (b));
+  EXPECT_EQ (42, bitmap_first_set_bit (b));
+
+  bitmap_set_range (b, 1066, 1);
+  EXPECT_FALSE (bitmap_single_bit_set_p (b));
+  EXPECT_EQ (42, bitmap_first_set_bit (b));
+
+  bitmap_clear_range (b, 0, 100);
+  EXPECT_TRUE (bitmap_single_bit_set_p (b));
+  EXPECT_EQ (1066, bitmap_first_set_bit (b));
+}
+
+}  // anon namespace
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 03/17] Add test-cfg.c to gcc/unittests
  2015-06-10 15:10 [PATCH 00/17] RFC: Addding a unit testing framework to gcc David Malcolm
                   ` (9 preceding siblings ...)
  2015-06-10 15:10 ` [PATCH 07/17] Add test-gimple.c " David Malcolm
@ 2015-06-10 15:17 ` David Malcolm
  2015-06-23 19:26   ` Jeff Law
  2015-06-10 15:25 ` [PATCH 17/17] toplev.c: move location_adhoc_data_fini call David Malcolm
                   ` (7 subsequent siblings)
  18 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-06-10 15:17 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/unittests/ChangeLog:
	* test-cfg.c: New file.
---
 gcc/unittests/test-cfg.c | 319 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 319 insertions(+)
 create mode 100644 gcc/unittests/test-cfg.c

diff --git a/gcc/unittests/test-cfg.c b/gcc/unittests/test-cfg.c
new file mode 100644
index 0000000..4781092
--- /dev/null
+++ b/gcc/unittests/test-cfg.c
@@ -0,0 +1,319 @@
+/* Unit tests for CFG-handling.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 <gtest/gtest.h>
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "pretty-print.h"
+#include "tree-cfg.h"
+#include "predict.h"
+#include "basic-block.h"
+#include "hard-reg-set.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+
+namespace {
+
+class cfg_test : public ::testing::Test
+{
+ protected:
+  tree
+  push_fndecl (const char *name)
+  {
+    tree fn_type = build_function_type_array (integer_type_node, /* return_type */
+					    0, NULL);
+    /* FIXME: this uses input_location: */
+    tree fndecl = build_fn_decl (name, fn_type);
+    tree retval = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+			      NULL_TREE, integer_type_node);
+    DECL_RESULT (fndecl) = retval;
+    push_struct_function (fndecl);
+    function *fun = DECL_STRUCT_FUNCTION (fndecl);
+    EXPECT_TRUE (fun != NULL);
+    init_empty_tree_cfg_for_function (fun);
+    EXPECT_EQ (2, n_basic_blocks_for_fn (fun));
+    EXPECT_EQ (0, n_edges_for_fn (fun));
+    return fndecl;
+  }
+};
+
+/* These tests directly create CFGs.
+   Compare with the static fns within tree-cfg.c:
+     - build_gimple_cfg
+     - make_blocks: calls create_basic_block (seq, bb);
+     - make_edges.   */
+
+/* Verify a simple cfg of the form:
+     ENTRY -> A -> B -> C -> EXIT.  */
+TEST_F (cfg_test, linear_chain)
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_test_linear_chain");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  EXPECT_TRUE (fun != NULL);
+
+  EXPECT_EQ (2, n_basic_blocks_for_fn (fun));
+  EXPECT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create some empty blocks.  */
+  basic_block bb_a = create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun));
+  basic_block bb_b = create_empty_bb (bb_a);
+  basic_block bb_c = create_empty_bb (bb_b);
+
+  EXPECT_EQ (5, n_basic_blocks_for_fn (fun));
+  EXPECT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create some edges: a simple linear chain of BBs.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), bb_a, EDGE_FALLTHRU);
+  make_edge (bb_a, bb_b, 0);
+  make_edge (bb_b, bb_c, 0);
+  make_edge (bb_c, EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+
+  /* Verify the edges.  */
+  EXPECT_EQ (4, n_edges_for_fn (fun));
+  EXPECT_EQ (NULL, ENTRY_BLOCK_PTR_FOR_FN (fun)->preds);
+  EXPECT_EQ (1, ENTRY_BLOCK_PTR_FOR_FN (fun)->succs->length ());
+  EXPECT_EQ (1, bb_a->preds->length ());
+  EXPECT_EQ (1, bb_a->succs->length ());
+  EXPECT_EQ (1, bb_b->preds->length ());
+  EXPECT_EQ (1, bb_b->succs->length ());
+  EXPECT_EQ (1, bb_c->preds->length ());
+  EXPECT_EQ (1, bb_c->succs->length ());
+  EXPECT_EQ (1, EXIT_BLOCK_PTR_FOR_FN (fun)->preds->length ());
+  EXPECT_EQ (NULL, EXIT_BLOCK_PTR_FOR_FN (fun)->succs);
+
+  /* Verify the dominance information
+     Each BB in our simple chain should be dominated by the one before
+     it.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  EXPECT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
+  EXPECT_EQ (bb_b, get_immediate_dominator (CDI_DOMINATORS, bb_c));
+  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
+  EXPECT_EQ (1, dom_by_b.length ());
+  EXPECT_EQ (bb_c, dom_by_b[0]);
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance: each BB in our chain is post-dominated
+     by the one after it.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  EXPECT_EQ (bb_b, get_immediate_dominator (CDI_POST_DOMINATORS, bb_a));
+  EXPECT_EQ (bb_c, get_immediate_dominator (CDI_POST_DOMINATORS, bb_b));
+  vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
+  EXPECT_EQ (1, postdom_by_b.length ());
+  EXPECT_EQ (bb_a, postdom_by_b[0]);
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+/* Verify a simple CFG of the form:
+     ENTRY
+       |
+       A
+      / \
+     /t  \f
+    B     C
+     \   /
+      \ /
+       D
+       |
+      EXIT.  */
+TEST_F (cfg_test, diamond)
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_test_diamond");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  EXPECT_TRUE (fun != NULL);
+
+  EXPECT_EQ (2, n_basic_blocks_for_fn (fun));
+  EXPECT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create some empty blocks.  */
+  basic_block bb_a = create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun));
+  basic_block bb_b = create_empty_bb (bb_a);
+  basic_block bb_c = create_empty_bb (bb_a);
+  basic_block bb_d = create_empty_bb (bb_b);
+
+  EXPECT_EQ (6, n_basic_blocks_for_fn (fun));
+  EXPECT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create the edges.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), bb_a, EDGE_FALLTHRU);
+  make_edge (bb_a, bb_b, EDGE_TRUE_VALUE);
+  make_edge (bb_a, bb_c, EDGE_FALSE_VALUE);
+  make_edge (bb_b, bb_d, 0);
+  make_edge (bb_c, bb_d, 0);
+  make_edge (bb_d, EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+
+  /* Verify the edges.  */
+  EXPECT_EQ (6, n_edges_for_fn (fun));
+  EXPECT_EQ (1, bb_a->preds->length ());
+  EXPECT_EQ (2, bb_a->succs->length ());
+  EXPECT_EQ (1, bb_b->preds->length ());
+  EXPECT_EQ (1, bb_b->succs->length ());
+  EXPECT_EQ (1, bb_c->preds->length ());
+  EXPECT_EQ (1, bb_c->succs->length ());
+  EXPECT_EQ (2, bb_d->preds->length ());
+  EXPECT_EQ (1, bb_d->succs->length ());
+
+  /* Verify the dominance information.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  EXPECT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
+  EXPECT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_c));
+  EXPECT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_d));
+  vec<basic_block> dom_by_a = get_dominated_by (CDI_DOMINATORS, bb_a);
+  EXPECT_EQ (3, dom_by_a.length ()); /* B, C, D, in some order.  */
+  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
+  EXPECT_EQ (0, dom_by_b.length ());
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  EXPECT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_a));
+  EXPECT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_b));
+  EXPECT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_c));
+  vec<basic_block> postdom_by_d = get_dominated_by (CDI_POST_DOMINATORS, bb_d);
+  EXPECT_EQ (3, postdom_by_d.length ()); /* A, B, C in some order.  */
+  vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
+  EXPECT_EQ (0, postdom_by_b.length ());
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+/* Verify that we can handle a CFG containing a "complete" aka
+   fully-connected subgraph (where A B C D below all have edges
+   pointing to each other node, also to themselves).
+   e.g.:
+     ENTRY  EXIT
+       |    ^
+       |   /
+       |  /
+       | /
+       V/
+       A<--->B
+       ^^   ^^
+       | \ / |
+       |  X  |
+       | / \ |
+       VV   VV
+       C<--->D
+*/
+TEST_F (cfg_test, fully_connected)
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_fully_connected");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  EXPECT_TRUE (fun != NULL);
+
+  EXPECT_EQ (2, n_basic_blocks_for_fn (fun));
+  EXPECT_EQ (0, n_edges_for_fn (fun));
+
+  const int n = 4;
+
+  /* Create some empty blocks.  */
+  auto_vec <basic_block> subgraph_nodes;
+  for (int i = 0; i < n; i++)
+    subgraph_nodes.safe_push (create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun)));
+
+  EXPECT_EQ (n + 2, n_basic_blocks_for_fn (fun));
+  EXPECT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create the edges.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), subgraph_nodes[0], EDGE_FALLTHRU);
+  make_edge (subgraph_nodes[0], EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+  for (int i = 0; i < n; i++)
+    for (int j = 0; j < n; j++)
+      make_edge (subgraph_nodes[i], subgraph_nodes[j], 0);
+
+  /* Verify the edges.  */
+  EXPECT_EQ (2 + (n * n), n_edges_for_fn (fun));
+  /* The first one is linked to ENTRY/EXIT as well as itself and
+     everything else.  */
+  EXPECT_EQ (n + 1, subgraph_nodes[0]->preds->length ());
+  EXPECT_EQ (n + 1, subgraph_nodes[0]->succs->length ());
+  /* The other ones in the subgraph are linked to everything in
+     the subgraph (including themselves).  */
+  for (int i = 1; i < n; i++)
+    {
+      EXPECT_EQ (n, subgraph_nodes[i]->preds->length ());
+      EXPECT_EQ (n, subgraph_nodes[i]->succs->length ());
+    }
+
+  /* Verify the dominance information.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  /* The initial block in the subgraph should be dominated by ENTRY.  */
+  EXPECT_EQ (ENTRY_BLOCK_PTR_FOR_FN (fun),
+	     get_immediate_dominator (CDI_DOMINATORS,
+				      subgraph_nodes[0]));
+  /* Every other block in the subgraph should be dominated by the
+     initial block.  */
+  for (int i = 1; i < n; i++)
+    EXPECT_EQ (subgraph_nodes[0],
+	       get_immediate_dominator (CDI_DOMINATORS,
+					subgraph_nodes[i]));
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  /* The initial block in the subgraph should be postdominated by EXIT.  */
+  EXPECT_EQ (EXIT_BLOCK_PTR_FOR_FN (fun),
+	     get_immediate_dominator (CDI_POST_DOMINATORS,
+				      subgraph_nodes[0]));
+  /* Every other block in the subgraph should be postdominated by the
+     initial block, since that leads to EXIT.  */
+  for (int i = 1; i < n; i++)
+    EXPECT_EQ (subgraph_nodes[0],
+	       get_immediate_dominator (CDI_POST_DOMINATORS,
+					subgraph_nodes[i]));
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+}  /* anon namespace.  */
+
+/* TODO: test the dominator/postdominator logic with various graphs/nodes:
+   - loop
+   - nested loops
+   - switch statement (a block with many out-edges)
+   - something that jumps to itself
+   - etc  */
+
+/* TODO: add tests for loop-detection here?  */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 17/17] toplev.c: move location_adhoc_data_fini call
  2015-06-10 15:10 [PATCH 00/17] RFC: Addding a unit testing framework to gcc David Malcolm
                   ` (10 preceding siblings ...)
  2015-06-10 15:17 ` [PATCH 03/17] Add test-cfg.c " David Malcolm
@ 2015-06-10 15:25 ` David Malcolm
  2015-06-10 15:26 ` [PATCH 13/17] Add test-vec.c to gcc/unittests David Malcolm
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-06-10 15:25 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

test-functions.c: representation_test.building_cfg and others
need the call to location_adhoc_data_fini to happen later, otherwise
we get a segfault inside gimple_set_block here due to the
adhoc-location data being finalized:

 #0  0x0000000000687800 in ?? ()
 #1  0x00007ffff7504c22 in htab_find_slot (htab=0x6627a0, element=0x7fffffffde90, insert=INSERT)
     at ../../src/libiberty/hashtab.c:704
 #2  0x00007ffff74c0de5 in get_combined_adhoc_loc (set=0x7ffff7ffa000, locus=<optimized out>, data=<optimized out>)
     at ../../src/libcpp/line-map.c:128
 #3  0x00007ffff73cb047 in COMBINE_LOCATION_DATA (block=<optimized out>, loc=<optimized out>, set=<optimized out>)
     at ../../src/gcc/../libcpp/include/line-map.h:794
 #4  gimple_set_block (g=<optimized out>, block=<optimized out>) at ../../src/gcc/gimple.h:1636
 #5  lower_stmt (data=0x7fffffffdfa0, gsi=0x7fffffffdf00) at ../../src/gcc/gimple-low.c:260
 #6  lower_sequence (seq=seq@entry=0x7fffefa310b8, data=data@entry=0x7fffffffdfa0) at ../../src/gcc/gimple-low.c:227
 #7  0x00007ffff73caeef in lower_gimple_bind (gsi=gsi@entry=0x7fffffffdfc0, data=data@entry=0x7fffffffdfa0)
     at ../../src/gcc/gimple-low.c:441
 #8  0x00007ffff73cc675 in lower_function_body () at ../../src/gcc/gimple-low.c:131
 #9  (anonymous namespace)::pass_lower_cf::execute (this=<optimized out>) at ../../src/gcc/gimple-low.c:205
 #10 0x0000000000414030 in (anonymous namespace)::representation_test::build_cfg (this=0x66c520, fndecl=0x7fffefa43ee0)
     at ../../src/gcc/unittests/test-functions.c:293
 #11 0x000000000041787d in (anonymous namespace)::representation_test_building_cfg_Test::TestBody (this=0x66c520)
     at ../../src/gcc/unittests/test-functions.c:501
 #12 0x00007ffff7dcf323 in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) () from /lib64/libgtest.so.0
 #13 0x00007ffff7dc4b67 in testing::Test::Run() () from /lib64/libgtest.so.0
 #14 0x00007ffff7dc4c0e in testing::TestInfo::Run() () from /lib64/libgtest.so.0
 #15 0x00007ffff7dc4d15 in testing::TestCase::Run() () from /lib64/libgtest.so.0
 #16 0x00007ffff7dc83a8 in testing::internal::UnitTestImpl::RunAllTests() () from /lib64/libgtest.so.0
 #17 0x00007ffff7dc8647 in testing::UnitTest::Run() () from /lib64/libgtest.so.0
 #18 0x00000000004369cb in main (argc=1, argv=0x7fffffffe478) at ../../src/gcc/unittests/unittests-main.c:107

gcc/ChangeLog:
	* toplev.c (toplev::main): Move call of
	location_adhoc_data_fini from here...
	(toplev::finalize): ...to here.
---
 gcc/toplev.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/gcc/toplev.c b/gcc/toplev.c
index 3b57b48..ca2c18c 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -2194,7 +2194,6 @@ toplev::main (int argc, char **argv)
   diagnostic_finish (global_dc);
 
   finalize_plugins ();
-  location_adhoc_data_fini (line_table);
   if (seen_error () || werrorcount)
     return (FATAL_EXIT_CODE);
 
@@ -2230,4 +2229,6 @@ toplev::finalize (void)
   g = NULL;
 
   obstack_free (&opts_obstack, NULL);
+
+  location_adhoc_data_fini (line_table);
 }
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 13/17] Add test-vec.c to gcc/unittests
  2015-06-10 15:10 [PATCH 00/17] RFC: Addding a unit testing framework to gcc David Malcolm
                   ` (11 preceding siblings ...)
  2015-06-10 15:25 ` [PATCH 17/17] toplev.c: move location_adhoc_data_fini call David Malcolm
@ 2015-06-10 15:26 ` David Malcolm
  2015-06-10 15:26 ` [PATCH 16/17] Add unittests-main.c " David Malcolm
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-06-10 15:26 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/unittests/ChangeLog:
	* test-vec.c: New file.
---
 gcc/unittests/test-vec.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 162 insertions(+)
 create mode 100644 gcc/unittests/test-vec.c

diff --git a/gcc/unittests/test-vec.c b/gcc/unittests/test-vec.c
new file mode 100644
index 0000000..5ea6ca3
--- /dev/null
+++ b/gcc/unittests/test-vec.c
@@ -0,0 +1,162 @@
+/* Unit tests for vec<>.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 <gtest/gtest.h>
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "vec.h"
+
+namespace {
+
+class vec_test : public ::testing::Test
+{
+ protected:
+  /* Add the range [START..LIMIT) to V.  */
+  void
+  safe_push_range (vec <int>&v, int start, int limit)
+  {
+    for (int i = start; i < limit; i++)
+      v.safe_push (i);
+  }
+};
+
+TEST_F (vec_test, quick_push)
+{
+  auto_vec <int> v;
+  EXPECT_EQ (0, v.length ());
+  v.reserve (3);
+  EXPECT_EQ (0, v.length ());
+  EXPECT_TRUE (v.space (3));
+  v.quick_push (5);
+  v.quick_push (6);
+  v.quick_push (7);
+  EXPECT_EQ (3, v.length ());
+  EXPECT_EQ (5, v[0]);
+  EXPECT_EQ (6, v[1]);
+  EXPECT_EQ (7, v[2]);
+}
+
+TEST_F (vec_test, safe_push)
+{
+  auto_vec <int> v;
+  EXPECT_EQ (0, v.length ());
+  v.safe_push (5);
+  v.safe_push (6);
+  v.safe_push (7);
+  EXPECT_EQ (3, v.length ());
+  EXPECT_EQ (5, v[0]);
+  EXPECT_EQ (6, v[1]);
+  EXPECT_EQ (7, v[2]);
+}
+
+TEST_F (vec_test, truncate)
+{
+  auto_vec <int> v;
+  EXPECT_EQ (0, v.length ());
+  safe_push_range (v, 0, 10);
+  EXPECT_EQ (10, v.length ());
+
+  v.truncate (5);
+  EXPECT_EQ (5, v.length ());
+}
+
+TEST_F (vec_test, safe_grow_cleared)
+{
+  auto_vec <int> v;
+  EXPECT_EQ (0, v.length ());
+  v.safe_grow_cleared (50);
+  EXPECT_EQ (50, v.length ());
+  EXPECT_EQ (0, v[0]);
+  EXPECT_EQ (0, v[49]);
+}
+
+TEST_F (vec_test, pop)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 5, 20);
+  EXPECT_EQ (15, v.length ());
+
+  int last = v.pop ();
+  EXPECT_EQ (19, last);
+  EXPECT_EQ (14, v.length ());
+}
+
+TEST_F (vec_test, safe_insert)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.safe_insert (5, 42);
+  EXPECT_EQ (4, v[4]);
+  EXPECT_EQ (42, v[5]);
+  EXPECT_EQ (5, v[6]);
+  EXPECT_EQ (11, v.length ());
+}
+
+TEST_F (vec_test, ordered_remove)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.ordered_remove (5);
+  EXPECT_EQ (4, v[4]);
+  EXPECT_EQ (6, v[5]);
+  EXPECT_EQ (9, v.length ());
+}
+
+TEST_F (vec_test, unordered_remove)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.unordered_remove (5);
+  EXPECT_EQ (9, v.length ());
+}
+
+TEST_F (vec_test, block_remove)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.block_remove (5, 3);
+  EXPECT_EQ (3, v[3]);
+  EXPECT_EQ (4, v[4]);
+  EXPECT_EQ (8, v[5]);
+  EXPECT_EQ (9, v[6]);
+  EXPECT_EQ (7, v.length ());
+}
+
+static int reverse_cmp (const void *p_i, const void *p_j)
+{
+  return *(const int *)p_j - *(const int *)p_i;
+}
+
+TEST_F (vec_test, qsort)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.qsort (reverse_cmp);
+  EXPECT_EQ (9, v[0]);
+  EXPECT_EQ (8, v[1]);
+  EXPECT_EQ (1, v[8]);
+  EXPECT_EQ (0, v[9]);
+  EXPECT_EQ (10, v.length ());
+}
+
+}  // anon namespace
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 16/17] Add unittests-main.c to gcc/unittests
  2015-06-10 15:10 [PATCH 00/17] RFC: Addding a unit testing framework to gcc David Malcolm
                   ` (12 preceding siblings ...)
  2015-06-10 15:26 ` [PATCH 13/17] Add test-vec.c to gcc/unittests David Malcolm
@ 2015-06-10 15:26 ` David Malcolm
  2015-06-10 15:28 ` [PATCH 15/17] Add unittests-frontend.c " David Malcolm
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-06-10 15:26 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/unittests/ChangeLog:
	* unittests-main.c: New file.
---
 gcc/unittests/unittests-main.c | 108 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 108 insertions(+)
 create mode 100644 gcc/unittests/unittests-main.c

diff --git a/gcc/unittests/unittests-main.c b/gcc/unittests/unittests-main.c
new file mode 100644
index 0000000..635a4f3
--- /dev/null
+++ b/gcc/unittests/unittests-main.c
@@ -0,0 +1,108 @@
+/* "main" and other top-level hooks for unittesting GCC.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 <gtest/gtest.h>
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "hard-reg-set.h"
+#include "input.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "gimple-expr.h"
+#include "toplev.h"
+
+namespace {
+
+class gcc_environment : public ::testing::Environment
+{
+ public:
+  gcc_environment ()
+    : m_toplev (true, /* use_TV_TOTAL */
+		false /* init_signals */)
+  {
+  }
+
+  /* Implementation of base class' vfunc.  */
+  void SetUp()
+  {
+    /* Hack: run toplev::main once, to force initialization.  */
+    auto_vec <const char *> args;
+    args.safe_push ("unittesting");
+    args.safe_push ("-quiet");
+
+    /* Hack: give it fake src/dst files, otherwise e.g. asm_out_file
+       becomes stdout, and we have an eventual crash.  */
+    args.safe_push ("-o");
+    args.safe_push ("/tmp/fake.s");
+    args.safe_push ("/tmp/fake.c");
+
+    m_toplev.main (args.length (),
+		   const_cast <char **> (args.address ()));
+
+    /* We've now run toplev once; everything should now be initialized
+       enough to allow use to run unit tests of the various subsystems.  */
+  }
+
+  /* Implementation of base class' vfunc.  */
+  void TearDown()
+  {
+    m_toplev.finalize ();
+  }
+
+ private:
+  toplev m_toplev;
+};
+
+}  // anon namespace
+
+int main (int argc, char **argv)
+{
+  ::testing::InitGoogleTest(&argc, argv);
+
+  ::testing::AddGlobalTestEnvironment(new gcc_environment);
+
+  return RUN_ALL_TESTS();
+}
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 06/17] Add test-ggc.c to gcc/unittests
  2015-06-10 15:10 [PATCH 00/17] RFC: Addding a unit testing framework to gcc David Malcolm
                   ` (14 preceding siblings ...)
  2015-06-10 15:28 ` [PATCH 15/17] Add unittests-frontend.c " David Malcolm
@ 2015-06-10 15:28 ` David Malcolm
  2015-06-10 15:34 ` [PATCH 14/17] Add test-wide-int.c " David Malcolm
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-06-10 15:28 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/unittests/ChangeLog:
	* test-ggc.c: New file.
---
 gcc/unittests/test-ggc.c | 292 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 292 insertions(+)
 create mode 100644 gcc/unittests/test-ggc.c

diff --git a/gcc/unittests/test-ggc.c b/gcc/unittests/test-ggc.c
new file mode 100644
index 0000000..9168b71
--- /dev/null
+++ b/gcc/unittests/test-ggc.c
@@ -0,0 +1,292 @@
+/* Unit tests for GCC's garbage collector (and gengtype etc).
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 <gtest/gtest.h>
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "ggc-internal.h" /* (for ggc_force_collect).  */
+
+/* The various GTY markers must be outside of a namespace to be seen by
+   gengtype, so we don't put this file within an anonymous namespace.  */
+
+/* A test fixture for writing ggc tests.  */
+class ggc_test : public ::testing::Test
+{
+ protected:
+  void
+  forcibly_ggc_collect ()
+  {
+    ggc_force_collect = true;
+    ggc_collect ();
+    ggc_force_collect = false;
+  }
+};
+
+/* Smoketest to ensure that a GC root is marked ("tree" type).  */
+
+static GTY(()) tree dummy_unittesting_tree;
+
+TEST_F (ggc_test, tree_marking)
+{
+  dummy_unittesting_tree = build_int_cst (integer_type_node, 1066);
+
+  forcibly_ggc_collect ();
+
+  EXPECT_TRUE (ggc_marked_p (dummy_unittesting_tree));
+}
+
+/* Verify that a simple custom struct works, and that it can
+   own references to non-roots, and have them be marked.  */
+
+struct GTY(()) test_struct
+{
+  test_struct *other;
+};
+
+static GTY(()) test_struct *root_test_struct;
+
+TEST_F (ggc_test, custom_struct)
+{
+  root_test_struct = ggc_cleared_alloc <test_struct> ();
+  root_test_struct->other = ggc_cleared_alloc <test_struct> ();
+
+  forcibly_ggc_collect ();
+
+  EXPECT_TRUE (ggc_marked_p (root_test_struct));
+  EXPECT_TRUE (ggc_marked_p (root_test_struct->other));
+}
+
+/* Verify that destructors get run when instances are collected.  */
+
+struct GTY(()) test_struct_with_dtor
+{
+  /* This struct has a destructor; it *ought* to be called
+     by the ggc machinery when instances are collected.  */
+  ~test_struct_with_dtor () { dtor_call_count++; }
+
+  static int dtor_call_count;
+};
+
+int test_struct_with_dtor::dtor_call_count;
+
+TEST_F (ggc_test, finalization)
+{
+  EXPECT_FALSE (need_finalization_p <test_struct> ());
+  EXPECT_TRUE (need_finalization_p <test_struct_with_dtor> ());
+
+  /* Create some garbage.  */
+  const int count = 10;
+  for (int i = 0; i < count; i++)
+    ggc_cleared_alloc <test_struct_with_dtor> ();
+
+  test_struct_with_dtor::dtor_call_count = 0;
+
+  forcibly_ggc_collect ();
+
+  /* Verify that the destructor was run for each instance.  */
+  EXPECT_EQ (count, test_struct_with_dtor::dtor_call_count);
+}
+
+/* Verify that a global can be marked as "deletable".  */
+
+static GTY((deletable)) test_struct *test_of_deletable;
+
+TEST_F (ggc_test, deletable_global)
+{
+  test_of_deletable = ggc_cleared_alloc <test_struct> ();
+  EXPECT_TRUE (test_of_deletable != NULL);
+
+  forcibly_ggc_collect ();
+
+  EXPECT_EQ (NULL, test_of_deletable);
+}
+
+/* Verify that gengtype etc can cope with inheritance.  */
+
+class GTY((desc("%h.m_kind"), tag("0"))) example_base
+{
+ public:
+  example_base ()
+    : m_kind (0),
+      m_a (ggc_cleared_alloc <test_struct> ())
+  {}
+
+  void *
+  operator new (size_t sz)
+  {
+    return ggc_internal_cleared_alloc (sz);
+  }
+
+ protected:
+  example_base (int kind)
+    : m_kind (kind),
+      m_a (ggc_cleared_alloc <test_struct> ())
+  {}
+
+ public:
+  int m_kind;
+  test_struct *m_a;
+};
+
+class GTY((tag("1"))) some_subclass : public example_base
+{
+ public:
+  some_subclass ()
+    : example_base (1),
+      m_b (ggc_cleared_alloc <test_struct> ())
+  {}
+
+  test_struct *m_b;
+};
+
+class GTY((tag("2"))) some_other_subclass : public example_base
+{
+ public:
+  some_other_subclass ()
+    : example_base (2),
+      m_c (ggc_cleared_alloc <test_struct> ())
+  {}
+
+  test_struct *m_c;
+};
+
+/* Various test roots, both expressed as a ptr to the actual class, and
+   as a ptr to the base class.  */
+static GTY(()) example_base *test_example_base;
+static GTY(()) some_subclass *test_some_subclass;
+static GTY(()) some_other_subclass *test_some_other_subclass;
+static GTY(()) example_base *test_some_subclass_as_base_ptr;
+static GTY(()) example_base *test_some_other_subclass_as_base_ptr;
+
+TEST_F (ggc_test, inheritance)
+{
+  test_example_base = new example_base ();
+  test_some_subclass = new some_subclass ();
+  test_some_other_subclass = new some_other_subclass ();
+  test_some_subclass_as_base_ptr = new some_subclass ();
+  test_some_other_subclass_as_base_ptr = new some_other_subclass ();
+
+  forcibly_ggc_collect ();
+
+  /* Verify that the roots and everything referenced by them got marked
+     (both for fields in the base class and those in subclasses).  */
+  EXPECT_TRUE (ggc_marked_p (test_example_base));
+  EXPECT_TRUE (ggc_marked_p (test_example_base->m_a));
+
+  EXPECT_TRUE (ggc_marked_p (test_some_subclass));
+  EXPECT_TRUE (ggc_marked_p (test_some_subclass->m_a));
+  EXPECT_TRUE (ggc_marked_p (test_some_subclass->m_b));
+
+  EXPECT_TRUE (ggc_marked_p (test_some_other_subclass));
+  EXPECT_TRUE (ggc_marked_p (test_some_other_subclass->m_a));
+  EXPECT_TRUE (ggc_marked_p (test_some_other_subclass->m_c));
+
+  EXPECT_TRUE (ggc_marked_p (test_some_subclass_as_base_ptr));
+  EXPECT_TRUE (ggc_marked_p (test_some_subclass_as_base_ptr->m_a));
+  EXPECT_TRUE (ggc_marked_p (((some_subclass *)
+			      test_some_subclass_as_base_ptr)->m_b));
+
+  EXPECT_TRUE (ggc_marked_p (test_some_other_subclass_as_base_ptr));
+  EXPECT_TRUE (ggc_marked_p (test_some_other_subclass_as_base_ptr->m_a));
+  EXPECT_TRUE (ggc_marked_p (((some_other_subclass *)
+			      test_some_other_subclass_as_base_ptr)->m_c));
+}
+
+/* Test of chain_next/chain_prev
+
+   Construct a very long linked list, so that without
+   the chain_next/chain_prev optimization we'd have
+   a stack overflow when gt_ggc_mx_test_node recurses.  */
+
+struct GTY(( chain_next ("%h.m_next"),
+	     chain_prev ("%h.m_prev") )) test_node
+{
+  test_node *m_prev;
+  test_node *m_next;
+  int m_idx;
+};
+
+static GTY(()) test_node *root_test_node;
+
+TEST_F (ggc_test, chain_next)
+{
+  /* 2 million nodes (and thus the same number of stack frames) ought
+     to be deep enough to crash if gengtype has created something
+     that recurses.
+
+     This length reliably causes the test to segfault without the
+     chain_next/prev optimization on this box (Fedora 20 x86_64 with 128GB
+     of RAM), but causes this test to take about 0.5s, dominating the time
+     taken by the overall testsuite.
+
+     We could perhaps lower this by not increasing the stack size so much
+     in toplev.c, or perhaps reducing the stack size when running this
+     testcase.  */
+  const int count = 2000000;
+
+  /* Build the linked list.  */
+  root_test_node = ggc_cleared_alloc <test_node> ();
+  test_node *tail_node = root_test_node;
+  for (int i = 0; i < count; i++)
+    {
+      test_node *new_node = ggc_cleared_alloc <test_node> ();
+      tail_node->m_next = new_node;
+      new_node->m_prev = tail_node;
+      new_node->m_idx = i;
+      tail_node = new_node;
+    }
+
+  forcibly_ggc_collect ();
+
+  /* If we got here, we survived.  */
+
+  /* Verify that all nodes in the list were marked.  */
+  EXPECT_TRUE (ggc_marked_p (root_test_node));
+  test_node *iter_node = root_test_node->m_next;
+  for (int i = 0; i < count; i++)
+    {
+      EXPECT_TRUE (ggc_marked_p (iter_node));
+      EXPECT_EQ (i, iter_node->m_idx);
+      iter_node = iter_node->m_next;
+    }
+}
+
+/* Ideas for other tests:
+   - pch-handling  */
+
+#include "gt-unittests-test-ggc.h"
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 15/17] Add unittests-frontend.c to gcc/unittests
  2015-06-10 15:10 [PATCH 00/17] RFC: Addding a unit testing framework to gcc David Malcolm
                   ` (13 preceding siblings ...)
  2015-06-10 15:26 ` [PATCH 16/17] Add unittests-main.c " David Malcolm
@ 2015-06-10 15:28 ` David Malcolm
  2015-06-10 15:28 ` [PATCH 06/17] Add test-ggc.c " David Malcolm
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-06-10 15:28 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/unittests/ChangeLog:
	* unittests-frontend.c: New file.
---
 gcc/unittests/unittests-frontend.c | 250 +++++++++++++++++++++++++++++++++++++
 1 file changed, 250 insertions(+)
 create mode 100644 gcc/unittests/unittests-frontend.c

diff --git a/gcc/unittests/unittests-frontend.c b/gcc/unittests/unittests-frontend.c
new file mode 100644
index 0000000..701c184
--- /dev/null
+++ b/gcc/unittests/unittests-frontend.c
@@ -0,0 +1,250 @@
+/* Dummy "frontend" for use within unittests.
+   Copyright (C) 2013-2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "debug.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "hash-map.h"
+#include "is-a.h"
+#include "plugin-api.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "tm.h"
+#include "hard-reg-set.h"
+#include "function.h"
+#include "ipa-ref.h"
+#include "dumpfile.h"
+#include "cgraph.h"
+
+#include <mpfr.h>
+
+/* Language-dependent contents of a type.  */
+
+struct GTY(()) lang_type
+{
+  char dummy;
+};
+
+/* Language-dependent contents of a decl.  */
+
+struct GTY((variable_size)) lang_decl
+{
+  char dummy;
+};
+
+/* Language-dependent contents of an identifier.  This must include a
+   tree_identifier.  */
+
+struct GTY(()) lang_identifier
+{
+  struct tree_identifier common;
+};
+
+/* The resulting tree type.  */
+
+union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
+	   chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL")))
+lang_tree_node
+{
+  union tree_node GTY((tag ("0"),
+		       desc ("tree_node_structure (&%h)"))) generic;
+  struct lang_identifier GTY((tag ("1"))) identifier;
+};
+
+/* We don't use language_function.  */
+
+struct GTY(()) language_function
+{
+  int dummy;
+};
+
+/* GC-marking callback for use from unittests_root_tab.
+
+   If there's an active playback context, call its marking method
+   so that it can mark any pointers it references.  */
+
+static void my_ggc_walker (void *)
+{
+}
+
+const char *dummy;
+
+struct ggc_root_tab unittests_root_tab[] =
+  {
+    {
+      &dummy, 1, 0, my_ggc_walker, NULL
+    },
+    LAST_GGC_ROOT_TAB
+  };
+
+/* Language hooks.  */
+
+static bool
+unittests_langhook_init (void)
+{
+  static bool registered_root_tab = false;
+  if (!registered_root_tab)
+    {
+      ggc_register_root_tab (unittests_root_tab);
+      registered_root_tab = true;
+    }
+
+  build_common_tree_nodes (false, false);
+
+  /* I don't know why this has to be done explicitly.  */
+  void_list_node = build_tree_list (NULL_TREE, void_type_node);
+
+  build_common_builtin_nodes ();
+
+  /* The default precision for floating point numbers.  This is used
+     for floating point constants with abstract type.  This may
+     eventually be controllable by a command line option.  */
+  mpfr_set_default_prec (256);
+
+  return true;
+}
+
+static void
+unittests_langhook_parse_file (void)
+{
+}
+
+static tree
+unittests_langhook_type_for_mode (enum machine_mode mode, int unsignedp)
+{
+  if (mode == TYPE_MODE (float_type_node))
+    return float_type_node;
+
+  if (mode == TYPE_MODE (double_type_node))
+    return double_type_node;
+
+  if (mode == TYPE_MODE (integer_type_node))
+    return unsignedp ? unsigned_type_node : integer_type_node;
+
+  if (mode == TYPE_MODE (long_integer_type_node))
+    return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+
+  if (COMPLEX_MODE_P (mode))
+    {
+      if (mode == TYPE_MODE (complex_float_type_node))
+	return complex_float_type_node;
+      if (mode == TYPE_MODE (complex_double_type_node))
+	return complex_double_type_node;
+      if (mode == TYPE_MODE (complex_long_double_type_node))
+	return complex_long_double_type_node;
+      if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp)
+	return complex_integer_type_node;
+    }
+
+  /* gcc_unreachable */
+  return NULL;
+}
+
+static tree
+unittests_langhook_type_for_size (unsigned int bits ATTRIBUTE_UNUSED,
+			    int unsignedp ATTRIBUTE_UNUSED)
+{
+  gcc_unreachable ();
+  return NULL;
+}
+
+/* Record a builtin function.  We just ignore builtin functions.  */
+
+static tree
+unittests_langhook_builtin_function (tree decl)
+{
+  return decl;
+}
+
+static bool
+unittests_langhook_global_bindings_p (void)
+{
+  gcc_unreachable ();
+  return true;
+}
+
+static tree
+unittests_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED)
+{
+  gcc_unreachable ();
+}
+
+static tree
+unittests_langhook_getdecls (void)
+{
+  return NULL;
+}
+
+static void
+unittests_langhook_write_globals (void)
+{
+  /* This is the hook that runs the middle and backends: */
+  symtab->finalize_compilation_unit ();
+}
+
+#undef LANG_HOOKS_NAME
+#define LANG_HOOKS_NAME		"unittests"
+
+#undef LANG_HOOKS_INIT
+#define LANG_HOOKS_INIT		unittests_langhook_init
+
+#undef LANG_HOOKS_PARSE_FILE
+#define LANG_HOOKS_PARSE_FILE		unittests_langhook_parse_file
+
+#undef LANG_HOOKS_TYPE_FOR_MODE
+#define LANG_HOOKS_TYPE_FOR_MODE	unittests_langhook_type_for_mode
+
+#undef LANG_HOOKS_TYPE_FOR_SIZE
+#define LANG_HOOKS_TYPE_FOR_SIZE	unittests_langhook_type_for_size
+
+#undef LANG_HOOKS_BUILTIN_FUNCTION
+#define LANG_HOOKS_BUILTIN_FUNCTION	unittests_langhook_builtin_function
+
+#undef LANG_HOOKS_GLOBAL_BINDINGS_P
+#define LANG_HOOKS_GLOBAL_BINDINGS_P	unittests_langhook_global_bindings_p
+
+#undef LANG_HOOKS_PUSHDECL
+#define LANG_HOOKS_PUSHDECL		unittests_langhook_pushdecl
+
+#undef LANG_HOOKS_GETDECLS
+#define LANG_HOOKS_GETDECLS		unittests_langhook_getdecls
+
+#undef LANG_HOOKS_WRITE_GLOBALS
+#define LANG_HOOKS_WRITE_GLOBALS	unittests_langhook_write_globals
+
+struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
+
+#include "gt-unittests-unittests-frontend.h"
+#include "gtype-unittests.h"
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 14/17] Add test-wide-int.c to gcc/unittests
  2015-06-10 15:10 [PATCH 00/17] RFC: Addding a unit testing framework to gcc David Malcolm
                   ` (15 preceding siblings ...)
  2015-06-10 15:28 ` [PATCH 06/17] Add test-ggc.c " David Malcolm
@ 2015-06-10 15:34 ` David Malcolm
  2015-06-10 16:19 ` [PATCH 00/17] RFC: Addding a unit testing framework to gcc Jakub Jelinek
  2015-06-11 14:49 ` Martin Liška
  18 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-06-10 15:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/unittests/ChangeLog:
	* test-wide-int.c: New file.
---
 gcc/unittests/test-wide-int.c | 186 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 186 insertions(+)
 create mode 100644 gcc/unittests/test-wide-int.c

diff --git a/gcc/unittests/test-wide-int.c b/gcc/unittests/test-wide-int.c
new file mode 100644
index 0000000..089e80d
--- /dev/null
+++ b/gcc/unittests/test-wide-int.c
@@ -0,0 +1,186 @@
+/* Unit tests for wide-int.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 <gtest/gtest.h>
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "wide-int-print.h"
+
+namespace {
+
+/* The types we will run the testcases for.  */
+typedef ::testing::Types<wide_int, offset_int, widest_int> implementations;
+
+/* A fixture for running the same tests for all of the wide-int.h types
+   listed in "implementations" above.
+
+   Unfortunately, for some reason gtest reports all of the tests as:
+   of type "<type>":
+     [----------] 2 tests from wide_int_test/0, where TypeParam = <type>
+       (snip)
+     [----------] 2 tests from wide_int_test/0 (0 ms total)
+     [----------] 2 tests from wide_int_test/1, where TypeParam = <type>
+       (snip)
+     [----------] 2 tests from wide_int_test/1 (0 ms total)
+     [----------] 2 tests from wide_int_test/2, where TypeParam = <type>
+       (snip)
+     [----------] 2 tests from wide_int_test/2 (0 ms total)
+*/
+
+template <class VALUE_TYPE>
+class wide_int_test : public ::testing::Test
+{
+ protected:
+  /* Helper function for building a test value.  */
+  VALUE_TYPE from_int (int i);
+};
+
+TYPED_TEST_CASE(wide_int_test, implementations);
+
+/* Specializations of the fixture for each wide-int type.  */
+
+template <>
+wide_int
+wide_int_test <wide_int>::from_int (int i)
+{
+  return wi::shwi (i, 32);
+}
+
+template <>
+offset_int
+wide_int_test <offset_int>::from_int (int i)
+{
+  return offset_int (i);
+}
+
+template <>
+widest_int
+wide_int_test <widest_int>::from_int (int i)
+{
+  return widest_int (i);
+}
+
+/* Verify that print_dec (WI, ..., SGN) gives the expected string
+   representation (using base 10).  */
+
+void
+expect_deceq (const char *expected, const wide_int_ref &wi, signop sgn)
+{
+  char buf[WIDE_INT_PRINT_BUFFER_SIZE];
+  print_dec (wi, buf, sgn);
+  EXPECT_STREQ (expected, buf);
+}
+
+/* Likewise for base 16.  */
+
+void
+expect_hexeq (const char *expected, const wide_int_ref &wi)
+{
+  char buf[WIDE_INT_PRINT_BUFFER_SIZE];
+  print_hex (wi, buf);
+  EXPECT_STREQ (expected, buf);
+}
+
+/* Test cases.  These will be run for each type in "implementations" above,
+   with gtest's TYPED_TEST macro defining the types "TypeParam"
+   and "TestFixture".  */
+
+TYPED_TEST (wide_int_test, test_printing)
+{
+  TypeParam a = TestFixture::from_int (42);
+  expect_deceq ("42", a, SIGNED);
+  expect_hexeq ("0x2a", a);
+}
+
+TYPED_TEST (wide_int_test, test_ops)
+{
+  TypeParam a = TestFixture::from_int (7);
+  TypeParam b = TestFixture::from_int (3);
+
+  /* Using functions.  */
+  expect_deceq ("-7", wi::neg (a), SIGNED);
+  expect_deceq ("10", wi::add (a, b), SIGNED);
+  expect_deceq ("4", wi::sub (a, b), SIGNED);
+  expect_deceq ("-4", wi::sub (b, a), SIGNED);
+  expect_deceq ("21", wi::mul (a, b), SIGNED);
+
+  /* Using operators.  */
+  expect_deceq ("-7", -a, SIGNED);
+  expect_deceq ("10", a + b, SIGNED);
+  expect_deceq ("4", a - b, SIGNED);
+  expect_deceq ("-4", b - a, SIGNED);
+  expect_deceq ("21", a * b, SIGNED);
+}
+
+TYPED_TEST (wide_int_test, test_comparisons)
+{
+  TypeParam a = TestFixture::from_int (7);
+  TypeParam b = TestFixture::from_int (3);
+
+  /* == */
+  EXPECT_TRUE (wi::eq_p (a, a));
+  EXPECT_FALSE (wi::eq_p (a, b));
+
+  /* != */
+  EXPECT_TRUE (wi::ne_p (a, b));
+  EXPECT_FALSE (wi::ne_p (a, a));
+
+  /* < */
+  EXPECT_FALSE (wi::lts_p (a, a));
+  EXPECT_FALSE (wi::lts_p (a, b));
+  EXPECT_TRUE (wi::lts_p (b, a));
+
+  /* <= */
+  EXPECT_TRUE (wi::les_p (a, a));
+  EXPECT_FALSE (wi::les_p (a, b));
+  EXPECT_TRUE (wi::les_p (b, a));
+
+  /* > */
+  EXPECT_FALSE (wi::gts_p (a, a));
+  EXPECT_TRUE (wi::gts_p (a, b));
+  EXPECT_FALSE (wi::gts_p (b, a));
+
+  /* >= */
+  EXPECT_TRUE (wi::ges_p (a, a));
+  EXPECT_TRUE (wi::ges_p (a, b));
+  EXPECT_FALSE (wi::ges_p (b, a));
+
+  /* comparison */
+  EXPECT_EQ (-1, wi::cmps (b, a));
+  EXPECT_EQ (0, wi::cmps (a, a));
+  EXPECT_EQ (1, wi::cmps (a, b));
+}
+
+}  /* anon namespace.  */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/17] RFC: Addding a unit testing framework to gcc
  2015-06-10 15:10 [PATCH 00/17] RFC: Addding a unit testing framework to gcc David Malcolm
                   ` (16 preceding siblings ...)
  2015-06-10 15:34 ` [PATCH 14/17] Add test-wide-int.c " David Malcolm
@ 2015-06-10 16:19 ` Jakub Jelinek
  2015-06-10 16:25   ` Richard Biener
                     ` (2 more replies)
  2015-06-11 14:49 ` Martin Liška
  18 siblings, 3 replies; 176+ messages in thread
From: Jakub Jelinek @ 2015-06-10 16:19 UTC (permalink / raw)
  To: David Malcolm; +Cc: gcc-patches

On Wed, Jun 10, 2015 at 11:24:41AM -0400, David Malcolm wrote:
> I picked the Google Test framework:
>   http://code.google.com/p/googletest/

I must say I'm not very excited about using this, it won't integrate
very well with dejagnu, whether talking about results (will it provide
some *.log/*.sum file with FAIL/XFAIL/PASS/XPASS etc. lines?), choosing
what options to use, e.g. global
RUNTESTFLAGS='--target_board=unix/\{-m32,-m64\}'
to test everything twice for 32-bit and 64-bit, will that run just
all unittests twice the same?, or possibility to run a subset of tests
etc.
E.g. for asan.exp testing, I just wrote a gtest emulation using
dejagnu, see testsuite/g++.dg/asan/dejagnu-gtest.h and
testsuite/lib/asan-dg.exp, but that was mainly meant for cases where
many routines are expected to crash the process.  If in unittests
you are doing only operations that aren't meant to take everything down or
if they crash, it is ok if it breaks the whole unit testing,
then perhaps it can be run as a single process and thus a single dejagnu
job, and just let the wrapper parse the output and transform it.

Also, no matter what testsuite framework is used, including any
headers before #include "config.h" line is a big no-no.

	Jakub

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/17] RFC: Addding a unit testing framework to gcc
  2015-06-10 16:19 ` [PATCH 00/17] RFC: Addding a unit testing framework to gcc Jakub Jelinek
@ 2015-06-10 16:25   ` Richard Biener
  2015-06-10 17:56   ` David Malcolm
  2015-06-10 18:21   ` David Malcolm
  2 siblings, 0 replies; 176+ messages in thread
From: Richard Biener @ 2015-06-10 16:25 UTC (permalink / raw)
  To: Jakub Jelinek, David Malcolm; +Cc: gcc-patches

On June 10, 2015 5:34:47 PM GMT+02:00, Jakub Jelinek <jakub@redhat.com> wrote:
>On Wed, Jun 10, 2015 at 11:24:41AM -0400, David Malcolm wrote:
>> I picked the Google Test framework:
>>   http://code.google.com/p/googletest/
>
>I must say I'm not very excited about using this, it won't integrate
>very well with dejagnu, whether talking about results (will it provide
>some *.log/*.sum file with FAIL/XFAIL/PASS/XPASS etc. lines?), choosing
>what options to use, e.g. global
>RUNTESTFLAGS='--target_board=unix/\{-m32,-m64\}'
>to test everything twice for 32-bit and 64-bit, will that run just
>all unittests twice the same?, or possibility to run a subset of tests
>etc.
>E.g. for asan.exp testing, I just wrote a gtest emulation using
>dejagnu, see testsuite/g++.dg/asan/dejagnu-gtest.h and
>testsuite/lib/asan-dg.exp, but that was mainly meant for cases where
>many routines are expected to crash the process.  If in unittests
>you are doing only operations that aren't meant to take everything down
>or
>if they crash, it is ok if it breaks the whole unit testing,
>then perhaps it can be run as a single process and thus a single
>dejagnu
>job, and just let the wrapper parse the output and transform it.
>
>Also, no matter what testsuite framework is used, including any
>headers before #include "config.h" line is a big no-no.

Agreed.  I think it is reasonable to instead do like the two existing tests - piggy back on a plugin testcase.

Richard.

>	Jakub


^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/17] RFC: Addding a unit testing framework to gcc
  2015-06-10 16:19 ` [PATCH 00/17] RFC: Addding a unit testing framework to gcc Jakub Jelinek
  2015-06-10 16:25   ` Richard Biener
@ 2015-06-10 17:56   ` David Malcolm
  2015-06-10 23:42     ` Jakub Jelinek
                       ` (2 more replies)
  2015-06-10 18:21   ` David Malcolm
  2 siblings, 3 replies; 176+ messages in thread
From: David Malcolm @ 2015-06-10 17:56 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On Wed, 2015-06-10 at 17:34 +0200, Jakub Jelinek wrote:
> On Wed, Jun 10, 2015 at 11:24:41AM -0400, David Malcolm wrote:
> > I picked the Google Test framework:
> >   http://code.google.com/p/googletest/
> 
> I must say I'm not very excited about using this, it won't integrate
> very well with dejagnu

Why is that a goal?  I've been using DejaGnu's unittesting API for
testing the jit, and it is... suboptimal, to put it mildly.

> whether talking about results (will it provide
> some *.log/*.sum file with FAIL/XFAIL/PASS/XPASS etc. lines?),

It doesn't have an output formatter for the DejaGnu format, but I guess
I could write one.  The gtest standard output format is IMHO superior to
DejaGnu's since it tells you start-of-test/end-of-test on separate
lines, so you can see which test killed things in the event of total
failure, and the per-test timings (which can be disabled if you want to
do diffs).

>  choosing
> what options to use, e.g. global
> RUNTESTFLAGS='--target_board=unix/\{-m32,-m64\}'
> to test everything twice for 32-bit and 64-bit, will that run just
> all unittests twice the same?,

Fair enough; yes, as written, RUNTESTFLAGS is ignored; it will run
everything once.  However we could express such a loop directly in the
"main" of the 

> or possibility to run a subset of tests

$ LD_LIBRARY_PATH=. ./unittests.exe --gtest_filter="*push"
Note: Google Test filter = *push
[==========] Running 2 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 2 tests from vec_test
[ RUN      ] vec_test.quick_push
[       OK ] vec_test.quick_push (0 ms)
[ RUN      ] vec_test.safe_push
[       OK ] vec_test.safe_push (0 ms)
[----------] 2 tests from vec_test (1 ms total)

[----------] Global test environment tear-down
[==========] 2 tests from 1 test case ran. (4 ms total)
[  PASSED  ] 2 tests.

> etc.
> E.g. for asan.exp testing, I just wrote a gtest emulation using
> dejagnu, see testsuite/g++.dg/asan/dejagnu-gtest.h and
> testsuite/lib/asan-dg.exp

...which doesn't have things like EXPECT_STREQ, or custom comparators,
doesn't appear to support fixtures, type-parameterized tests,
value-parameterized tests, etc, my point being that a unit-testing
framework is a non-trivial amount of code that could do useful things
for us.

> but that was mainly meant for cases where
> many routines are expected to crash the process.

FWIW, if I'm reading testsuite/g++.dg/asan/dejagnu-gtest.h and
testsuite/lib/asan-dg.exp correctly, it looks like you're spawning the
tool once per EXPECT_DEATH instance in the testsuite.  That seems
suboptimal, gtest uses fork without exec
to do it all directly at the point of the test without lots of extra
work, where the parent verifies the death of the child.

>   If in unittests
> you are doing only operations that aren't meant to take everything down or
> if they crash, it is ok if it breaks the whole unit testing,
> then perhaps it can be run as a single process and thus a single dejagnu
> job, and just let the wrapper parse the output and transform it.

I guess, but having used google test lately, DejaGnu feels like a big
step backwards.

> Also, no matter what testsuite framework is used, including any
> headers before #include "config.h" line is a big no-no.

OK.  Can't remember why I did that.


Dave

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/17] RFC: Addding a unit testing framework to gcc
  2015-06-10 16:19 ` [PATCH 00/17] RFC: Addding a unit testing framework to gcc Jakub Jelinek
  2015-06-10 16:25   ` Richard Biener
  2015-06-10 17:56   ` David Malcolm
@ 2015-06-10 18:21   ` David Malcolm
  2015-06-10 22:15     ` Jakub Jelinek
  2 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-06-10 18:21 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On Wed, 2015-06-10 at 17:34 +0200, Jakub Jelinek wrote:
> On Wed, Jun 10, 2015 at 11:24:41AM -0400, David Malcolm wrote:
(...snip...)

> Also, no matter what testsuite framework is used, including any
> headers before #include "config.h" line is a big no-no.

The issue was that libiberty/safe-ctype.h
has various macros of the form:
  #define toupper(c) do_not_use_toupper_with_safe_ctype

which, if I include gtest.h last, breaks the STL e.g. in 
      const char_type*
      toupper(char_type *__lo, const char_type* __hi) const
      { return this->do_toupper(__lo, __hi); }

/usr/include/c++/4.8.3/bits/locale_facets.h:240:53: error: macro
"toupper" passed 2 arguments, but takes just 1
       toupper(char_type *__lo, const char_type* __hi) const
                                                     ^
Adding a #undef of these things before including gtest.h fixes it,
though we then run into:

In file included from /usr/include/gtest/internal/gtest-internal.h:40:0,
                 from /usr/include/gtest/gtest.h:57,
                 from ../../src/gcc/unittests/test-tree.c:73:
/usr/include/gtest/internal/gtest-port.h:1595:47: error: attempt to use
poisoned "strdup"
 inline char* StrDup(const char* src) { return strdup(src); }
                                               ^
/usr/include/gtest/internal/gtest-port.h:1638:50: error: attempt to use
poisoned "strerror"
 inline const char* StrError(int errnum) { return strerror(errnum); }
                                                  ^

FWIW this goes away if I simply include gtest.h immediately after
config.h, but before system.h.


Dave

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/17] RFC: Addding a unit testing framework to gcc
  2015-06-10 18:21   ` David Malcolm
@ 2015-06-10 22:15     ` Jakub Jelinek
  0 siblings, 0 replies; 176+ messages in thread
From: Jakub Jelinek @ 2015-06-10 22:15 UTC (permalink / raw)
  To: David Malcolm; +Cc: gcc-patches

On Wed, Jun 10, 2015 at 02:04:11PM -0400, David Malcolm wrote:
> FWIW this goes away if I simply include gtest.h immediately after
> config.h, but before system.h.

Yeah, I guess including it before system.h and after config.h is fine.

	Jakub

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/17] RFC: Addding a unit testing framework to gcc
  2015-06-10 17:56   ` David Malcolm
@ 2015-06-10 23:42     ` Jakub Jelinek
  2015-06-17 20:36       ` [PATCH/RFC]: unittesting v2: as a plugin (was Re: [PATCH 00/17] RFC: Addding a unit testing framework to gcc) David Malcolm
  2015-06-23 19:06     ` [PATCH 00/17] RFC: Addding a unit testing framework to gcc Jeff Law
  2015-06-23 20:04     ` Mike Stump
  2 siblings, 1 reply; 176+ messages in thread
From: Jakub Jelinek @ 2015-06-10 23:42 UTC (permalink / raw)
  To: David Malcolm; +Cc: gcc-patches

On Wed, Jun 10, 2015 at 01:16:20PM -0400, David Malcolm wrote:
> On Wed, 2015-06-10 at 17:34 +0200, Jakub Jelinek wrote:
> > On Wed, Jun 10, 2015 at 11:24:41AM -0400, David Malcolm wrote:
> > > I picked the Google Test framework:
> > >   http://code.google.com/p/googletest/
> > 
> > I must say I'm not very excited about using this, it won't integrate
> > very well with dejagnu
> 
> Why is that a goal?  I've been using DejaGnu's unittesting API for
> testing the jit, and it is... suboptimal, to put it mildly.

Primarily consistency, people want consistent output of the testresults from
the compiler, not to have to pass one set of magic options to dejagnu to do
something and then mirror them to something completely different to make
gtest happy.  Similarly, there are all kinds of scripts that analyze gcc
testresults, having to parse a completely different format because a tiny
percentage of tests runs something different isn't a very good idea.
Plus, by using googletest, you add another build requirement, we already
have quite a lot of them.

> > whether talking about results (will it provide
> > some *.log/*.sum file with FAIL/XFAIL/PASS/XPASS etc. lines?),
> 
> It doesn't have an output formatter for the DejaGnu format, but I guess
> I could write one.  The gtest standard output format is IMHO superior to
> DejaGnu's since it tells you start-of-test/end-of-test on separate
> lines, so you can see which test killed things in the event of total

I find the dejagnu log files quite readable, unlike the gtest stuff, so
supposedly this is quite subjective.

> > etc.
> > E.g. for asan.exp testing, I just wrote a gtest emulation using
> > dejagnu, see testsuite/g++.dg/asan/dejagnu-gtest.h and
> > testsuite/lib/asan-dg.exp
> 
> ...which doesn't have things like EXPECT_STREQ, or custom comparators,
> doesn't appear to support fixtures, type-parameterized tests,
> value-parameterized tests, etc, my point being that a unit-testing
> framework is a non-trivial amount of code that could do useful things
> for us.

The question is why you really need it, or if it is more than a few lines of
macros.

> > but that was mainly meant for cases where
> > many routines are expected to crash the process.
> 
> FWIW, if I'm reading testsuite/g++.dg/asan/dejagnu-gtest.h and
> testsuite/lib/asan-dg.exp correctly, it looks like you're spawning the
> tool once per EXPECT_DEATH instance in the testsuite.  That seems
> suboptimal, gtest uses fork without exec
> to do it all directly at the point of the test without lots of extra
> work, where the parent verifies the death of the child.

That was a design choice, makes it much easier to debug the individual
tests, especially for asan where for gtest there are just way too many forks
and way too many (expected) crashes.
For the unittests, I see no problem running numerous tests from within one
process, it can emit multiple PASS/FAIL/XFAIL etc.

	Jakub

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/17] RFC: Addding a unit testing framework to gcc
  2015-06-10 15:10 [PATCH 00/17] RFC: Addding a unit testing framework to gcc David Malcolm
                   ` (17 preceding siblings ...)
  2015-06-10 16:19 ` [PATCH 00/17] RFC: Addding a unit testing framework to gcc Jakub Jelinek
@ 2015-06-11 14:49 ` Martin Liška
  18 siblings, 0 replies; 176+ messages in thread
From: Martin Liška @ 2015-06-11 14:49 UTC (permalink / raw)
  To: gcc-patches

On 06/10/2015 05:24 PM, David Malcolm wrote:
> Our current test suite is rather coarse-grained, acting at the level
> of running gcc subprocesses, and verifying externally-visible
> properties:
>    - Did the compile succeed?
>    - Was a particular dumpfile emitted, containing something matching
>      some regex?
>    - Does the generated code run and exit gracefully?
> etc
>
> The strength of this approach is that we have good "integration"
> coverage: we know that the compiler runs and generates good code.
> However it's slow, and doesn't allow very precise control over what
> properties we can assert.
>
> The following patch kit adds a suite of unit tests to gcc, aimed at
> giving test coverage for properties that are difficult to test for
> in the current system.  For example, there are tests of ggc to
> verify that gengtype is doing sane things, of various container
> classes (vec, hash_map, hash_set) and of wide-int.  Some of the
> tests are rather "placeholdery" e.g. the tests of folding trees,
> where there's plenty of room for adding new testcases.
>
> I've split them up into multiple patches for ease of review, but
> they all stand together.
>
> I picked the Google Test framework:
>    http://code.google.com/p/googletest/
>
> I didn't do a very thorough survey of C++ test frameworks; I picked
> this one as it's used by several very large projects (including
> LLVM [1]), and is actively maintained.  Working with it has largely been
> a pleasant experience: it generates good error messages when tests
> fail (e.g. with enough information so that I can click on failures
> in Emacs and have it go to the failing test), and is sane to work
> with in gdb.  The log is easy to read; I've added an example to
> the end of this mail.  It supports parameterizing testcases across
> multiple types (I use this for testing wide-int).
>
> The only other "framework" I've used has been the DejaGnu unittest
> header, which I use for the jit testsuite; I can't recommend it (it's
> a pain to use, and I've had to extend it repeatedly to get basic
> functionality like string equality assertions).
>
> The testsuite is intended to be very fast, all in one process, and it
> takes less than a second to run; it fact, the time is dominated by a
> single very slow test, which takes 300-400ms to run, but which could
> be sped up [2]; other than that, it takes about 10ms to run.
>
> Structurally, the patches add a "unittests" frontend: this is rather
> analogous to libgccjit.so: it's a dummy frontend.  The
> unittests/Make-lang.in builds a libgccunittests.so, which does
> nothing, stubbing out the frontend hooks, but provides a DSO holding
> the code to be tested.
>
> libgccunittests.so is then linked into a "unittests.exe" binary, which
> holds the actual testcases.  An advantage of this separation is that
> although linking libgccunittests.so is rather slow (like linking "cc1"
> etc), unittests.exe is very fast to link, so that it's very fast to
> hack on individual tests without needing to relink "everything" for
> each edit.
>
> Of course, this means that we can't unittest the real frontends this
> way (but we couldn't before, and maybe we can find a route to doing
> this).
>
> I have the Make-lang.in implementing the "unittests" target so that
> it builds and *runs* the unit tests i.e. if you do a "make", the
> unittests are run (rather than just on a "make check").  Given how
> fast they are (especially relative to "make check", the only issue
> I can see with this is the output log spew).  One nice thing about
> doing it there is that it can be run at each stage of a bootstrap,
> so hopefully we fail earlier when we're going to fail.
>
> I marked it in config-lang.in as
>    build_by_default="no"
> so you have to opt-in to building it by adding "unittests" to the
>    --enable-languages=
> configure options.
>
> The split of the bulk of the link into a libgccjitunittests.so
> means that it also requires the
>    --enable-host-shared
> configure-time option.
>
> It doesn't yet bootstrap; the link fails with:
> test-folding.o: In function `testing::AssertionResult testing::internal::CmpHelperNE<tree_node*, tree_node*>(char const*, char const*, tree_node* const&, tree_node* const&)':
> test-folding.c:(.text._ZN7testing8internal11CmpHelperNEIP9tree_nodeS3_EENS_15AssertionResultEPKcS6_RKT_RKT0_[_ZN7testing8internal11CmpHelperNEIP9tree_nodeS3_EENS_15AssertionResultEPKcS6_RKT_RKT0_]+0x26e): undefined reference to `testing::internal::StringStreamToString(std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >*)'
>
> though this was using a system copy of gtest
> (is this due to the C++ stdlib ABI change?  it seems to only affect
> tests using EXPECT_STREQ, and if I hack them out, it seems to work).
> (perhaps we'd need to bundle our own copy of gtest?)
>
> Here's a sample log (and it's sanely color-coded if you run it at
> a tty):
>
> $ make unittests
> [==========] Running 56 tests from 16 test cases.
> [----------] Global test environment set-up.
> [----------] 6 tests from ggc_test
> [ RUN      ] ggc_test.tree_marking
> [       OK ] ggc_test.tree_marking (0 ms)
> [ RUN      ] ggc_test.custom_struct
> [       OK ] ggc_test.custom_struct (0 ms)
> [ RUN      ] ggc_test.finalization
> [       OK ] ggc_test.finalization (0 ms)
> [ RUN      ] ggc_test.deletable_global
> [       OK ] ggc_test.deletable_global (1 ms)
> [ RUN      ] ggc_test.inheritance
> [       OK ] ggc_test.inheritance (0 ms)
> [ RUN      ] ggc_test.chain_next
> [       OK ] ggc_test.chain_next (326 ms)
> [----------] 6 tests from ggc_test (327 ms total)
>
> [----------] 5 tests from bitmap_test
> [ RUN      ] bitmap_test.gc_alloc
> [       OK ] bitmap_test.gc_alloc (0 ms)
> [ RUN      ] bitmap_test.set_range
> [       OK ] bitmap_test.set_range (0 ms)
> [ RUN      ] bitmap_test.clear_bit_in_middle
> [       OK ] bitmap_test.clear_bit_in_middle (0 ms)
> [ RUN      ] bitmap_test.copying
> [       OK ] bitmap_test.copying (0 ms)
> [ RUN      ] bitmap_test.bitmap_single_bit_set_p
> [       OK ] bitmap_test.bitmap_single_bit_set_p (0 ms)
> [----------] 5 tests from bitmap_test (0 ms total)
>
> [----------] 3 tests from cfg_test
> [ RUN      ] cfg_test.linear_chain
> [       OK ] cfg_test.linear_chain (1 ms)
> [ RUN      ] cfg_test.diamond
> [       OK ] cfg_test.diamond (0 ms)
> [ RUN      ] cfg_test.fully_connected
> [       OK ] cfg_test.fully_connected (0 ms)
> [----------] 3 tests from cfg_test (1 ms total)
>
> [----------] 1 test from tree_folding_test
> [ RUN      ] tree_folding_test.arithmetic_folding
> [       OK ] tree_folding_test.arithmetic_folding (0 ms)
> [----------] 1 test from tree_folding_test (0 ms total)
>
> [----------] 2 tests from function_test
> [ RUN      ] function_test.fndecl_int_void
> [       OK ] function_test.fndecl_int_void (0 ms)
> [ RUN      ] function_test.fndecl_float_intchar
> [       OK ] function_test.fndecl_float_intchar (0 ms)
> [----------] 2 tests from function_test (0 ms total)
>
> [----------] 4 tests from representation_test
> [ RUN      ] representation_test.gimplification
> [       OK ] representation_test.gimplification (0 ms)
> [ RUN      ] representation_test.building_cfg
> [       OK ] representation_test.building_cfg (0 ms)
> [ RUN      ] representation_test.conversion_to_ssa
> [       OK ] representation_test.conversion_to_ssa (0 ms)
> [ RUN      ] representation_test.expansion_to_rtl
> [       OK ] representation_test.expansion_to_rtl (6 ms)
> [----------] 4 tests from representation_test (6 ms total)
>
> [----------] 5 tests from gimple_test
> [ RUN      ] gimple_test.assign_single
> [       OK ] gimple_test.assign_single (0 ms)
> [ RUN      ] gimple_test.assign_binop
> [       OK ] gimple_test.assign_binop (0 ms)
> [ RUN      ] gimple_test.nop_stmt
> [       OK ] gimple_test.nop_stmt (0 ms)
> [ RUN      ] gimple_test.return_stmt
> [       OK ] gimple_test.return_stmt (0 ms)
> [ RUN      ] gimple_test.return_without_value
> [       OK ] gimple_test.return_without_value (0 ms)
> [----------] 5 tests from gimple_test (0 ms total)
>
> [----------] 1 test from hash_map_test
> [ RUN      ] hash_map_test.map_of_strings_to_int
> [       OK ] hash_map_test.map_of_strings_to_int (0 ms)
> [----------] 1 test from hash_map_test (0 ms total)
>
> [----------] 1 test from hash_set_test
> [ RUN      ] hash_set_test.set_of_strings
> [       OK ] hash_set_test.set_of_strings (0 ms)
> [----------] 1 test from hash_set_test (0 ms total)
>
> [----------] 4 tests from location_test
> [ RUN      ] location_test.accessing_ordinary_linemaps
> [       OK ] location_test.accessing_ordinary_linemaps (0 ms)
> [ RUN      ] location_test.unknown_location
> [       OK ] location_test.unknown_location (0 ms)
> [ RUN      ] location_test.builtins
> [       OK ] location_test.builtins (0 ms)
> [ RUN      ] location_test.reading_source_line
> [       OK ] location_test.reading_source_line (0 ms)
> [----------] 4 tests from location_test (0 ms total)
>
> [----------] 2 tests from rtl_test
> [ RUN      ] rtl_test.test_single_set
> [       OK ] rtl_test.test_single_set (0 ms)
> [ RUN      ] rtl_test.uncond_jump
> [       OK ] rtl_test.uncond_jump (0 ms)
> [----------] 2 tests from rtl_test (0 ms total)
>
> [----------] 3 tests from tree_test
> [ RUN      ] tree_test.integer_constants
> [       OK ] tree_test.integer_constants (0 ms)
> [ RUN      ] tree_test.identifiers
> [       OK ] tree_test.identifiers (0 ms)
> [ RUN      ] tree_test.labels
> [       OK ] tree_test.labels (0 ms)
> [----------] 3 tests from tree_test (0 ms total)
>
> [----------] 10 tests from vec_test
> [ RUN      ] vec_test.quick_push
> [       OK ] vec_test.quick_push (0 ms)
> [ RUN      ] vec_test.safe_push
> [       OK ] vec_test.safe_push (0 ms)
> [ RUN      ] vec_test.truncate
> [       OK ] vec_test.truncate (0 ms)
> [ RUN      ] vec_test.safe_grow_cleared
> [       OK ] vec_test.safe_grow_cleared (0 ms)
> [ RUN      ] vec_test.pop
> [       OK ] vec_test.pop (0 ms)
> [ RUN      ] vec_test.safe_insert
> [       OK ] vec_test.safe_insert (0 ms)
> [ RUN      ] vec_test.ordered_remove
> [       OK ] vec_test.ordered_remove (0 ms)
> [ RUN      ] vec_test.unordered_remove
> [       OK ] vec_test.unordered_remove (0 ms)
> [ RUN      ] vec_test.block_remove
> [       OK ] vec_test.block_remove (0 ms)
> [ RUN      ] vec_test.qsort
> [       OK ] vec_test.qsort (0 ms)
> [----------] 10 tests from vec_test (1 ms total)
>
> [----------] 3 tests from wide_int_test/0, where TypeParam = <type>
> [ RUN      ] wide_int_test/0.test_printing
> [       OK ] wide_int_test/0.test_printing (0 ms)
> [ RUN      ] wide_int_test/0.test_ops
> [       OK ] wide_int_test/0.test_ops (0 ms)
> [ RUN      ] wide_int_test/0.test_comparisons
> [       OK ] wide_int_test/0.test_comparisons (0 ms)
> [----------] 3 tests from wide_int_test/0 (0 ms total)
>
> [----------] 3 tests from wide_int_test/1, where TypeParam = <type>
> [ RUN      ] wide_int_test/1.test_printing
> [       OK ] wide_int_test/1.test_printing (0 ms)
> [ RUN      ] wide_int_test/1.test_ops
> [       OK ] wide_int_test/1.test_ops (0 ms)
> [ RUN      ] wide_int_test/1.test_comparisons
> [       OK ] wide_int_test/1.test_comparisons (0 ms)
> [----------] 3 tests from wide_int_test/1 (0 ms total)
>
> [----------] 3 tests from wide_int_test/2, where TypeParam = <type>
> [ RUN      ] wide_int_test/2.test_printing
> [       OK ] wide_int_test/2.test_printing (0 ms)
> [ RUN      ] wide_int_test/2.test_ops
> [       OK ] wide_int_test/2.test_ops (0 ms)
> [ RUN      ] wide_int_test/2.test_comparisons
> [       OK ] wide_int_test/2.test_comparisons (0 ms)
> [----------] 3 tests from wide_int_test/2 (0 ms total)
>
> [----------] Global test environment tear-down
> [==========] 56 tests from 16 test cases ran. (338 ms total)
> [  PASSED  ] 56 tests.
>
> Thoughts?
> Dave

Hi David.

I really like the idea to introduce a unit testing. Few months ago, when I was
working on adding support for negative number of sreal class, I needed a place
to write unit tests. In the end I wrote a plugin for GCC:

gcc/testsuite/gcc.dg/plugin/sreal_plugin.c

After you will merge the patch set, I will rewrite it to be part of unit tests.

Thanks,
Martin


>
> [1] though it's not clear to me if LLVM is actually still using it;
> see e.g. http://blog.llvm.org/2009/12/lit-it.html
> [2] the test of chain_next/chain_prev in test-ggc.c, which needed
> a very large linked list in order to reliably overflow the stack on
> my box; perhaps this could be eliminated by adding something to
> libiberty to shrink the stack size?
>
> David Malcolm (17):
>    Add Make-lang.in and config-lang.in to gcc/unittests
>    Add test-bitmap.c to gcc/unittests
>    Add test-cfg.c to gcc/unittests
>    Add test-folding.c to gcc/unittests
>    Add test-functions.c to gcc/unittests
>    Add test-ggc.c to gcc/unittests
>    Add test-gimple.c to gcc/unittests
>    Add test-hash-map.c to gcc/unittests
>    Add test-hash-set.c to gcc/unittests
>    Add test-locations.c to gcc/unittests
>    Add test-rtl.c to gcc/unittests
>    Add test-tree.c to gcc/unittests
>    Add test-vec.c to gcc/unittests
>    Add test-wide-int.c to gcc/unittests
>    Add unittests-frontend.c to gcc/unittests
>    Add unittests-main.c to gcc/unittests
>    toplev.c: move location_adhoc_data_fini call
>
>   gcc/toplev.c                       |   3 +-
>   gcc/unittests/Make-lang.in         | 200 ++++++++++++
>   gcc/unittests/config-lang.in       |  34 ++
>   gcc/unittests/test-bitmap.c        | 117 +++++++
>   gcc/unittests/test-cfg.c           | 319 +++++++++++++++++++
>   gcc/unittests/test-folding.c       | 121 +++++++
>   gcc/unittests/test-functions.c     | 634 +++++++++++++++++++++++++++++++++++++
>   gcc/unittests/test-ggc.c           | 292 +++++++++++++++++
>   gcc/unittests/test-gimple.c        | 179 +++++++++++
>   gcc/unittests/test-hash-map.c      |  78 +++++
>   gcc/unittests/test-hash-set.c      |  54 ++++
>   gcc/unittests/test-locations.c     | 148 +++++++++
>   gcc/unittests/test-rtl.c           |  94 ++++++
>   gcc/unittests/test-tree.c          | 102 ++++++
>   gcc/unittests/test-vec.c           | 162 ++++++++++
>   gcc/unittests/test-wide-int.c      | 186 +++++++++++
>   gcc/unittests/unittests-frontend.c | 250 +++++++++++++++
>   gcc/unittests/unittests-main.c     | 108 +++++++
>   18 files changed, 3080 insertions(+), 1 deletion(-)
>   create mode 100644 gcc/unittests/Make-lang.in
>   create mode 100644 gcc/unittests/config-lang.in
>   create mode 100644 gcc/unittests/test-bitmap.c
>   create mode 100644 gcc/unittests/test-cfg.c
>   create mode 100644 gcc/unittests/test-folding.c
>   create mode 100644 gcc/unittests/test-functions.c
>   create mode 100644 gcc/unittests/test-ggc.c
>   create mode 100644 gcc/unittests/test-gimple.c
>   create mode 100644 gcc/unittests/test-hash-map.c
>   create mode 100644 gcc/unittests/test-hash-set.c
>   create mode 100644 gcc/unittests/test-locations.c
>   create mode 100644 gcc/unittests/test-rtl.c
>   create mode 100644 gcc/unittests/test-tree.c
>   create mode 100644 gcc/unittests/test-vec.c
>   create mode 100644 gcc/unittests/test-wide-int.c
>   create mode 100644 gcc/unittests/unittests-frontend.c
>   create mode 100644 gcc/unittests/unittests-main.c
>

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH/RFC]: unittesting v2: as a plugin (was Re: [PATCH 00/17] RFC: Addding a unit testing framework to gcc)
  2015-06-10 23:42     ` Jakub Jelinek
@ 2015-06-17 20:36       ` David Malcolm
  2015-06-23 19:29         ` Jeff Law
  0 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-06-17 20:36 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 6752 bytes --]

On Thu, 2015-06-11 at 00:18 +0200, Jakub Jelinek wrote:
> On Wed, Jun 10, 2015 at 01:16:20PM -0400, David Malcolm wrote:
> > On Wed, 2015-06-10 at 17:34 +0200, Jakub Jelinek wrote:
> > > On Wed, Jun 10, 2015 at 11:24:41AM -0400, David Malcolm wrote:
> > > > I picked the Google Test framework:
> > > >   http://code.google.com/p/googletest/
> > > 
> > > I must say I'm not very excited about using this, it won't integrate
> > > very well with dejagnu
> > 
> > Why is that a goal?  I've been using DejaGnu's unittesting API for
> > testing the jit, and it is... suboptimal, to put it mildly.
> 
> Primarily consistency, people want consistent output of the testresults from
> the compiler, not to have to pass one set of magic options to dejagnu to do
> something and then mirror them to something completely different to make
> gtest happy.  Similarly, there are all kinds of scripts that analyze gcc
> testresults, having to parse a completely different format because a tiny
> percentage of tests runs something different isn't a very good idea.
> Plus, by using googletest, you add another build requirement, we already
> have quite a lot of them.

Thanks.

I've rewritten the patches so that instead of building a "frontend", it
instead builds a plugin: unittests_plugin.so, which runs the testsuite
within a PLUGIN_FINISH callback.  Doing so required a fair amount of
time in gdb dealing with state issues.

The plugin is referenced from a new testcase:
  c-c++-common/torture/run-unittests-plugin.c
which is simply:
 /* { dg-options "-fplugin=../../unittests_plugin.so" } */

leading to a unittest suite that's run repeatedly for both cc1 and
cc1plus, for all of the various torturing options.  

Presumably something similar could be added for the other frontends (I
tried for gfortran, but couldn't seem to get it to add the option to the
torture test, so the plugin didn't run).

> > > whether talking about results (will it provide
> > > some *.log/*.sum file with FAIL/XFAIL/PASS/XPASS etc. lines?),
> > 
> > It doesn't have an output formatter for the DejaGnu format, but I guess
> > I could write one.  The gtest standard output format is IMHO superior to
> > DejaGnu's since it tells you start-of-test/end-of-test on separate
> > lines, so you can see which test killed things in the event of total
> 
> I find the dejagnu log files quite readable, unlike the gtest stuff, so
> supposedly this is quite subjective.

I wrote a custom formatter for the output (class deja_gnu_printer within
unittests-plugin.c) which generates lines like this on stderr:

PASS: ggc_test.tree_marking
PASS: ggc_test.custom_struct
PASS: ggc_test.finalization
PASS: ggc_test.inheritance
PASS: ggc_test.chain_next

These get detected on stderr by some new logic inside
testsuite/lib/prune.exp, which prefixes them with
[testname-for-summary], and emitting them at the Tcl level, so they end
up in the .log and .sum files as lines like this:

PASS: c-c++-common/torture/run-unittests-plugin.c   -O0   ggc_test.tree_marking
PASS: c-c++-common/torture/run-unittests-plugin.c   -O0   ggc_test.custom_struct
PASS: c-c++-common/torture/run-unittests-plugin.c   -O0   ggc_test.finalization
PASS: c-c++-common/torture/run-unittests-plugin.c   -O0   ggc_test.inheritance
PASS: c-c++-common/torture/run-unittests-plugin.c   -O0   ggc_test.chain_next

(if doing it for all testcase output is an issue, perhaps this prune.exp
logic could be made conditional, so that we only do it for testcases
using the plugin, or that contain a dg command)

> > > etc.
> > > E.g. for asan.exp testing, I just wrote a gtest emulation using
> > > dejagnu, see testsuite/g++.dg/asan/dejagnu-gtest.h and
> > > testsuite/lib/asan-dg.exp
> > 
> > ...which doesn't have things like EXPECT_STREQ, or custom comparators,
> > doesn't appear to support fixtures, type-parameterized tests,
> > value-parameterized tests, etc, my point being that a unit-testing
> > framework is a non-trivial amount of code that could do useful things
> > for us.
> 
> The question is why you really need it, or if it is more than a few lines of
> macros.

I'm not sure.

gtest is available in collapsed form as a pair of .cc and .h files; in
my latest version, as an experiment, I embedded a copy of gtest-1.7 in
the source tree, as:
  gcc/unittests/gtest-all.c
  gcc/unittests/gtest/gtest.h
and they're built as part of the plugin.

This works, and means there's no extra external dependency, and I was
able to bootstrap with this.  I ran into an issue with "make check": the
plugin is linked against the previous stage's libstdc++, but "make
check" doesn't seem to set up LD_LIBRARY_PATH to point at a fresh
libstdc++ and uses the system copy, leading to
cc1: error: cannot load plugin ../../unittests_plugin.so
/lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required
by ../../unittests_plugin.so)

on this Fedora 20 box.  Manually setting LD_LIBRARY_PATH to point at the
built libstdc++ fixes it.

My higher-level goals here are:
  * to get test coverage of things like gengtype/ggc, our data
structures, etc.
  * to have an easy place for people to add unit-test coverage, without
needing to write a new plugin each time

It's clearly possible to write a family of macros that emulate the gtest
API.  However, if we also want e.g. fixture classes, I wonder at what
point it would be simpler to use gtest itself, rather than a
reimplementation of it (or some other framework).

Perhaps it would be simplest to have a minimal reimplementation of gtest
that mimics the API (although perhaps without the use of CamelCase?).

FWIW, I attempted to use the "Catch" unittest header
(https://github.com/philsquared/Catch) but it relies on exceptions, so
presumably that's a no-no.

> > > but that was mainly meant for cases where
> > > many routines are expected to crash the process.
> > 
> > FWIW, if I'm reading testsuite/g++.dg/asan/dejagnu-gtest.h and
> > testsuite/lib/asan-dg.exp correctly, it looks like you're spawning the
> > tool once per EXPECT_DEATH instance in the testsuite.  That seems
> > suboptimal, gtest uses fork without exec
> > to do it all directly at the point of the test without lots of extra
> > work, where the parent verifies the death of the child.
> 
> That was a design choice, makes it much easier to debug the individual
> tests, especially for asan where for gtest there are just way too many forks
> and way too many (expected) crashes.
> For the unittests, I see no problem running numerous tests from within one
> process, it can emit multiple PASS/FAIL/XFAIL etc.

(nods).

I'm attaching a patch; this is relative to the previous patch kit (since
this is more for discussion, as this clearly isn't ready yet), and omits
the embedded copies of gtest.

Thoughts?

Dave

[-- Attachment #2: unittests-v2.patch --]
[-- Type: text/x-patch, Size: 14539 bytes --]

commit f843bf0ed5764a36b0c0188c6d367b3164dfd34c
Author: David Malcolm <dmalcolm@redhat.com>
Date:   Wed Jun 17 15:27:53 2015 -0400

    Rewrite unittests to be a plugin

diff --git a/gcc/testsuite/c-c++-common/torture/run-unittests-plugin.c b/gcc/testsuite/c-c++-common/torture/run-unittests-plugin.c
new file mode 100644
index 0000000..297d78b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/run-unittests-plugin.c
@@ -0,0 +1,2 @@
+/* This source file leads to the unittests_plugin being loaded and run.
+   { dg-options "-fplugin=../../unittests_plugin.so" } */
diff --git a/gcc/testsuite/lib/prune.exp b/gcc/testsuite/lib/prune.exp
index 8e4c203..c5d24be 100644
--- a/gcc/testsuite/lib/prune.exp
+++ b/gcc/testsuite/lib/prune.exp
@@ -68,6 +68,48 @@ proc prune_gcc_output { text } {
     # Ignore harmless warnings from Xcode 4.0.
     regsub -all "(^|\n)\[^\n\]*ld: warning: could not create compact unwind for\[^\n\]*" $text "" text
 
+    # Process any DejaGnu output from the test, and convert into results at
+    # this level, prefixing with the testcase.
+    # For example, given the line
+    #   PASS: vec_test.quick_push
+    # from the test, we want to call "pass", giving a line like this in
+    # our .log/.sum, depending on [testname-for-summary]:
+    #   PASS: c-c++-common/torture/run-unittests-plugin.c   -O0   vec_test.quick_push
+    verbose "Would handle: $text\n"
+    # TODO: generalize for other kinds of test result:
+    foreach status_pair { {"PASS" pass} {"FAIL" fail} } {
+	set kind [lindex $status_pair 0]
+	set handler [lindex $status_pair 1]
+	#verbose "kind: $kind   handler: $handler"
+	set pattern "^$kind: (.*?)$"
+	#verbose "pattern: $pattern"
+	set matches [regexp -all -inline -lineanchor $pattern $text]
+	#verbose "matches: $matches"
+	foreach {matched_line detail} $matches {
+	    #verbose "matched_line: $matched_line"
+	    #verbose "detail: $detail"
+	    set testname [testname-for-summary]
+
+	    # Call the handler ("pass"/"fail" etc) to convert to a message
+	    # at this level, prefixed with [testname-for-summary]:
+	    $handler "$testname $detail"
+
+	    # Prune $matched_line from $text (or, at least, the first
+	    # instance of it).
+	    # Is there a less clunky way to do this?  (regsub would require
+	    # escaping any regex special characters within $matched_line).
+	    # Locate first instance of matched_line:
+	    set idx [string first $matched_line $text]
+	    # Get length, adding one for the trailing newline char:
+	    set linelen [expr [string length $matched_line] + 1]
+	    # Cut it out from the middle of $text:
+	    set textlen [string length $text]
+	    set before [string range $text 0 [expr $idx - 1] ]
+	    set after_ [string range $text [expr $idx + $linelen] $textlen]
+	    set text $before$after_
+	}
+    }
+
     #send_user "After:$text\n"
 
     return $text
diff --git a/gcc/unittests/Make-lang.in b/gcc/unittests/Make-lang.in
index 50d6e4f..26a0cb9 100644
--- a/gcc/unittests/Make-lang.in
+++ b/gcc/unittests/Make-lang.in
@@ -40,43 +40,33 @@
 # into the unittests rule, but that needs a little bit of work
 # to do the right thing within all.cross.
 
-LIBGCCUNITTESTS_LINKER_NAME = libgccunittests.so
-LIBGCCUNITTESTS_VERSION_NUM = 0
-LIBGCCUNITTESTS_MINOR_NUM = 0
-LIBGCCUNITTESTS_RELEASE_NUM = 1
-LIBGCCUNITTESTS_SONAME = $(LIBGCCUNITTESTS_LINKER_NAME).$(LIBGCCUNITTESTS_VERSION_NUM)
-LIBGCCUNITTESTS_FILENAME = \
-  $(LIBGCCUNITTESTS_SONAME).$(LIBGCCUNITTESTS_MINOR_NUM).$(LIBGCCUNITTESTS_RELEASE_NUM)
+UNITTESTS_PLUGIN_SO = unittests_plugin.so
 
-LIBGCCUNITTESTS_LINKER_NAME_SYMLINK = $(LIBGCCUNITTESTS_LINKER_NAME)
-LIBGCCUNITTESTS_SONAME_SYMLINK = $(LIBGCCUNITTESTS_SONAME)
-
-TESTPROGRAMS = unittests.exe
-
-RUN_TESTPROGRAMS = run-unittests.exe
-
-unittests: $(LIBGCCUNITTESTS_FILENAME) \
-	$(LIBGCCUNITTESTS_SYMLINK) \
-	$(LIBGCCUNITTESTS_LINKER_NAME_SYMLINK) \
+unittests: \
 	$(FULL_DRIVER_NAME) \
-	$(TESTPROGRAMS) \
-	$(RUN_TESTPROGRAMS)
+	$(UNITTESTS_PLUGIN_SO)
 
 # Tell GNU make to ignore these if they exist.
-.PHONY: unittests $(RUN_TESTPROGRAMS)
+.PHONY: unittests
 
-# "Frontend" objects, which go into libgccunittests.so
-unittests_OBJS = attribs.o \
-	unittests/unittests-frontend.o
+# gengtype integration
+gt-unittests-test-ggc.h: ./gengtype $(srcdir)/unittests/test-ggc.c
+	./gengtype \
+	  --plugin $@ \
+	  --read-state gtype.state \
+	  $(srcdir)/unittests/test-ggc.c
 
 # Build various files against gtest
 
 # Files that are linked into unittests.exe
-UNITTESTS_EXE_OBJS = \
+
+UNITTESTS_PLUGIN_SO_OBJS = \
+	gtest-all.o \
 	test-bitmap.o \
 	test-cfg.o \
 	test-folding.o \
 	test-functions.o \
+	test-ggc.o \
 	test-gimple.o \
 	test-hash-map.o \
 	test-hash-set.o \
@@ -85,11 +75,11 @@ UNITTESTS_EXE_OBJS = \
 	test-tree.o \
 	test-vec.o \
 	test-wide-int.o \
-	unittests-main.o
+	unittests-plugin.o
 
 # Files to be built against gtest
-# test-ggc.o has to be linked in to libgccunittests.so
-OBJS_BUILT_AGAINST_GTEST = $(UNITTESTS_EXE_OBJS) test-ggc.o
+# FIXME: do we still need this?
+OBJS_BUILT_AGAINST_GTEST = $(UNITTESTS_PLUGIN_SO_OBJS)
 
 # All objects (for the main Makefile.in's dependency tracking)
 #extra_OBJS += $(OBJS_BUILT_AGAINST_GTEST)
@@ -97,23 +87,6 @@ OBJS_BUILT_AGAINST_GTEST = $(UNITTESTS_EXE_OBJS) test-ggc.o
 # Use strict warnings for this front end.
 unittests-warn = $(STRICT_WARN)
 
-# We avoid using $(BACKEND) from Makefile.in in order to avoid pulling
-# in main.o
-$(LIBGCCUNITTESTS_FILENAME): $(unittests_OBJS) \
-	libbackend.a libcommon-target.a libcommon.a \
-	$(CPPLIB) $(LIBDECNUMBER) \
-	$(LIBDEPS) test-ggc.o
-	+$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ -shared \
-	     $(unittests_OBJS) libbackend.a libcommon-target.a libcommon.a \
-	     $(CPPLIB) $(LIBDECNUMBER) $(LIBS) $(BACKENDLIBS) test-ggc.o \
-	     -Wl,-soname,$(LIBGCCUNITTESTS_SONAME)
-
-$(LIBGCCUNITTESTS_SONAME_SYMLINK): $(LIBGCCUNITTESTS_FILENAME)
-	ln -sf $(LIBGCCUNITTESTS_FILENAME) $(LIBGCCUNITTESTS_SONAME_SYMLINK)
-
-$(LIBGCCUNITTESTS_LINKER_NAME_SYMLINK): $(LIBGCCUNITTESTS_SONAME_SYMLINK)
-	ln -sf $(LIBGCCUNITTESTS_SONAME_SYMLINK) $(LIBGCCUNITTESTS_LINKER_NAME_SYMLINK)
-
 #\f
 # Build hooks:
 
@@ -121,24 +94,31 @@ unittests.all.cross:
 unittests.start.encap:
 unittests.rest.encap:
 
-$(OBJS_BUILT_AGAINST_GTEST): %.o: $(srcdir)/unittests/%.c
+# Needed by gtest-all.c:
+#   -Wno-missing-field-initializers
+#   -Wno-conversion-null
+#   -Wno-suggest-attribute=format
+# Needed by various test-*.c:
+#   -Wno-sign-compare
+
+$(OBJS_BUILT_AGAINST_GTEST): %.o: $(srcdir)/unittests/%.c \
+	  gt-unittests-test-ggc.h
 	$(COMPILER) \
-	  $(shell gtest-config --cppflags --cxxflags) \
 	  $(INCLUDES) \
 	  $(ALL_COMPILERFLAGS) \
-	  -c -o $@ $<
-
-unittests.exe: $(UNITTESTS_EXE_OBJS) $(LIBGCCUNITTESTS_LINKER_NAME_SYMLINK)
+	  -c -o $@ $< \
+	-fPIC \
+	-Wno-missing-field-initializers \
+	-Wno-conversion-null \
+	-Wno-suggest-attribute=format \
+	-Wno-sign-compare
+
+$(UNITTESTS_PLUGIN_SO): $(UNITTESTS_PLUGIN_SO_OBJS)
 	$(LINKER) \
-	  $(shell gtest-config --ldflags --libs) \
-	  $(ALL_LINKERFLAGS) \
-	  -L. -lgccunittests \
 	  -o $@ \
-	  $(UNITTESTS_EXE_OBJS) \
-	  $(LIBGCCUNITTESTS_LINKER_NAME_SYMLINK)
-
-run-unittests.exe: unittests.exe
-	LD_LIBRARY_PATH=. ./unittests.exe
+	  -shared \
+	  $(UNITTESTS_PLUGIN_SO_OBJS) \
+	-lpthread
 
 # Documentation build hooks.
 unittests.info:
@@ -149,19 +129,7 @@ lang_checks += check-unittests
 
 #\f
 # Install hooks:
-unittests.install-common: installdirs
-	$(INSTALL_PROGRAM) $(LIBGCCUNITTESTS_FILENAME) \
-	  $(DESTDIR)/$(libdir)/$(LIBGCCUNITTESTS_FILENAME)
-	ln -sf \
-	  $(LIBGCCUNITTESTS_FILENAME) \
-	  $(DESTDIR)/$(libdir)/$(LIBGCCUNITTESTS_SONAME_SYMLINK)
-	ln -sf \
-	  $(LIBGCCUNITTESTS_SONAME_SYMLINK)\
-	  $(DESTDIR)/$(libdir)/$(LIBGCCUNITTESTS_LINKER_NAME_SYMLINK)
-	$(INSTALL_PROGRAM) $(srcdir)/unittests/libgccunittests.h \
-	  $(DESTDIR)/$(includedir)/libgccunittests.h
-	$(INSTALL_PROGRAM) $(srcdir)/unittests/libgccunittests++.h \
-	  $(DESTDIR)/$(includedir)/libgccunittests++.h
+unittests.install-common:
 
 unittests.install-man:
 
diff --git a/gcc/unittests/config-lang.in b/gcc/unittests/config-lang.in
index 1e0bfd7..0d24609 100644
--- a/gcc/unittests/config-lang.in
+++ b/gcc/unittests/config-lang.in
@@ -29,6 +29,6 @@ compilers="unittest-suite"
 
 target_libs=""
 
-gtfiles="\$(srcdir)/unittests/unittests-frontend.c \$(srcdir)/unittests/test-ggc.c"
+gtfiles=""
 
 build_by_default="no"
diff --git a/gcc/unittests/test-ggc.c b/gcc/unittests/test-ggc.c
index 197b4b5..4418a21 100644
--- a/gcc/unittests/test-ggc.c
+++ b/gcc/unittests/test-ggc.c
@@ -125,6 +125,12 @@ TEST_F (ggc_test, finalization)
 
 static GTY((deletable)) test_struct *test_of_deletable;
 
+/* FIXME: we can't do this test via a plugin as it stands.
+   The list of deletable roots is fixed by the main gengtype
+   run; there isn't yet a way to add extra
+   deletable roots (PLUGIN_REGISTER_GGC_ROOTS is for regular
+   roots).  */
+#if 0
 TEST_F (ggc_test, deletable_global)
 {
   test_of_deletable = ggc_cleared_alloc <test_struct> ();
@@ -134,6 +140,7 @@ TEST_F (ggc_test, deletable_global)
 
   EXPECT_EQ (NULL, test_of_deletable);
 }
+#endif
 
 /* Verify that gengtype etc can cope with inheritance.  */
 
diff --git a/gcc/unittests/unittests-plugin.c b/gcc/unittests/unittests-plugin.c
new file mode 100644
index 0000000..83dc4f3
--- /dev/null
+++ b/gcc/unittests/unittests-plugin.c
@@ -0,0 +1,182 @@
+/* Plugin that process internal tests for sreal.  */
+#include "config.h"
+#include "gtest/gtest.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "tm.h"
+#include "toplev.h"
+#include "hash-table.h"
+#include "vec.h"
+#include "ggc.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "tree-eh.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "intl.h"
+#include "context.h"
+#include "diagnostic.h"
+#include "bitmap.h"
+
+int plugin_is_GPL_compatible;
+
+/* Print test output in DejaGnu form.  */
+class deja_gnu_printer : public ::testing::EmptyTestEventListener
+{
+ public:
+  deja_gnu_printer (FILE *outfile, int verbose)
+    : m_outfile (outfile),
+      m_verbose (verbose)
+  {}
+
+ private:
+  virtual void
+  OnTestCaseStart(const ::testing::TestCase& test_case)
+  {
+    if (m_verbose)
+      fprintf (m_outfile, "NOTE: %s: case starting\n",
+	       test_case.name ());
+  }
+
+  /* Vfunc called before a test starts.  */
+  virtual void
+  OnTestStart (const ::testing::TestInfo& test_info)
+  {
+    if (m_verbose)
+      fprintf (m_outfile,
+	       "NOTE: %s.%s: test starting\n",
+	       test_info.test_case_name (), test_info.name ());
+    m_per_test_fails = 0;
+  }
+
+  /* Vfunc called after a failed assertion or a SUCCEED() invocation.  */
+  virtual void
+  OnTestPartResult (const ::testing::TestPartResult& test_part_result)
+  {
+    fprintf (m_outfile,
+	     "%s: %s:%d: %s\n",
+	     test_part_result.failed () ? "FAIL" : "PASS",
+	     test_part_result.file_name (),
+	     test_part_result.line_number (),
+	     test_part_result.summary ());
+    if (test_part_result.failed ())
+      m_per_test_fails++;
+  }
+
+  /* Vfunc called after a test ends.  */
+  virtual void
+  OnTestEnd (const ::testing::TestInfo& test_info)
+  {
+    if (m_verbose)
+      fprintf (m_outfile,
+	       "NOTE: %s.%s: test ending: %i failure(s)\n",
+	       test_info.test_case_name (), test_info.name (),
+	       m_per_test_fails);
+    fprintf (m_outfile,
+	     "%s: %s.%s\n",
+	     m_per_test_fails > 0 ? "FAIL" : "PASS",
+	     test_info.test_case_name (), test_info.name ());
+  }
+
+  virtual void
+  OnTestCaseEnd (const ::testing::TestCase& test_case)
+  {
+    if (m_verbose)
+      fprintf (m_outfile, "NOTE: %s: case ending\n",
+	       test_case.name ());
+  }
+
+ private:
+    FILE *m_outfile;
+    int m_verbose;
+    int m_per_test_fails;
+};
+
+/* Get rid of the default gtest result printer, and instead use LISTENER,
+   taking ownership of the ptr.  */
+
+static void
+replace_default_gtest_result_printer (::testing::TestEventListener *listener)
+{
+  ::testing::TestEventListeners& listeners =
+    ::testing::UnitTest::GetInstance()->listeners();
+  delete listeners.Release(listeners.default_result_printer());
+  listeners.Append(listener);
+}
+
+/* Callback handler for the PLUGIN_FINISH event.
+   At this point, all GCC subsystems should be initialized and
+   "warmed up"; this is where we run our unit tests.  */
+
+static void
+on_finish (void */*gcc_data*/, void */*user_data*/)
+{
+  /* FIXME: get these from the passed-in args to the plugin?
+     would we need to store them?  */
+  int argc = 0;
+  char **argv = NULL;
+  ::testing::InitGoogleTest (&argc, argv);
+
+  /* Use our custom result-printer.  */
+  replace_default_gtest_result_printer (new deja_gnu_printer (stderr, 0));
+
+  /* Reset some state.  */
+  input_location = UNKNOWN_LOCATION;
+  bitmap_obstack_initialize (NULL);
+
+  /* Run the tests.  */
+  int result = RUN_ALL_TESTS();
+
+  /* Ensure that a test failure leads to the process exiting with
+     a non-zero exit code.  */
+  if (result)
+    error ("at least one test failure occurred");
+
+  /* Cleanup.  */
+  bitmap_obstack_release (NULL);
+}
+
+/* Declared in "gt-unittests-test-ggc.h". */
+extern const struct ggc_root_tab gt_ggc_r_gt_unittests_test_ggc_h[];
+#if 0
+extern const struct ggc_root_tab gt_ggc_rd_gt_unittests_test_ggc_h[];
+#endif
+
+int
+plugin_init (struct plugin_name_args *plugin_info,
+	     struct plugin_gcc_version */*version*/)
+{
+  if (0)
+    fprintf (stderr, "got here\n");
+
+  register_callback (plugin_info->base_name,
+		     PLUGIN_REGISTER_GGC_ROOTS,
+		     NULL,
+		     const_cast <ggc_root_tab *> (
+		       gt_ggc_r_gt_unittests_test_ggc_h));
+  /* FIXME: we'd use this for test-ggc.c's test_of_deletable.
+     However we'd need to register it as a different kind of roottab;
+     doing it with PLUGIN_REGISTER_GGC_ROOTS leads to a segfault on
+     collection due to the NULL cb.
+     It looks like we need another hook; gt_ggc_deletable_rtab is
+     currently not expandable.  */
+#if 0
+  register_callback (plugin_info->base_name,
+		     PLUGIN_REGISTER_GGC_ROOTS,
+		     NULL,
+		     const_cast <ggc_root_tab *> (
+		       gt_ggc_rd_gt_unittests_test_ggc_h));
+#endif
+  register_callback (plugin_info->base_name,
+		     PLUGIN_FINISH,
+		     on_finish,
+		     NULL); /* void *user_data */
+
+  return 0;
+}

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/17] RFC: Addding a unit testing framework to gcc
  2015-06-10 17:56   ` David Malcolm
  2015-06-10 23:42     ` Jakub Jelinek
@ 2015-06-23 19:06     ` Jeff Law
  2015-06-23 20:04     ` Mike Stump
  2 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-06-23 19:06 UTC (permalink / raw)
  To: David Malcolm, Jakub Jelinek; +Cc: gcc-patches

On 06/10/2015 11:16 AM, David Malcolm wrote:
> On Wed, 2015-06-10 at 17:34 +0200, Jakub Jelinek wrote:
>> On Wed, Jun 10, 2015 at 11:24:41AM -0400, David Malcolm wrote:
>>> I picked the Google Test framework:
>>>    http://code.google.com/p/googletest/
>>
>> I must say I'm not very excited about using this, it won't integrate
>> very well with dejagnu
>
> Why is that a goal?  I've been using DejaGnu's unittesting API for
> testing the jit, and it is... suboptimal, to put it mildly.
Everyone on the project is already using dejagnu.  Adding another 
framework means everyone has to learn new ways of doing the same thing. 
  I think Jakub touched on multilibs, flag passing, result parsing, etc. 
    Note these things are embedded in the daily practices of many 
developers, build bots and even within our Makefiles for parallization 
of testing.

I'd be less likely to object if the google test framework was wrapped by 
dejagnu and had those low level things wired up properly.  I'd also be 
less likely to object if we converted *everything* to googletest.  The 
former is most likely orders of magnitude easier :-)


>
>> whether talking about results (will it provide
>> some *.log/*.sum file with FAIL/XFAIL/PASS/XPASS etc. lines?),
>
> It doesn't have an output formatter for the DejaGnu format, but I guess
> I could write one.  The gtest standard output format is IMHO superior to
> DejaGnu's since it tells you start-of-test/end-of-test on separate
> lines, so you can see which test killed things in the event of total
> failure, and the per-test timings (which can be disabled if you want to
> do diffs).
You can still get all that output if you wrap googletest with dejagnu -- 
that low level information would go into the .log file and the .sum 
would just have the pass, fail, xfail, xpass, etc messages.


>
>>   choosing
>> what options to use, e.g. global
>> RUNTESTFLAGS='--target_board=unix/\{-m32,-m64\}'
>> to test everything twice for 32-bit and 64-bit, will that run just
>> all unittests twice the same?,
>
> Fair enough; yes, as written, RUNTESTFLAGS is ignored; it will run
> everything once.  However we could express such a loop directly in the
> "main" of the
But using the syntax above is already well known by developers and 
build/test bots.  I'm not keen to change it.


And note, I *hate* dejagnu.

Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 02/17] Add test-bitmap.c to gcc/unittests
  2015-06-10 15:10 ` [PATCH 02/17] Add test-bitmap.c " David Malcolm
@ 2015-06-23 19:17   ` Jeff Law
  0 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-06-23 19:17 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 06/10/2015 09:24 AM, David Malcolm wrote:
> gcc/unittests/ChangeLog:
> 	* test-bitmap.c: New file.
> ---
>   gcc/unittests/test-bitmap.c | 117 ++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 117 insertions(+)
>   create mode 100644 gcc/unittests/test-bitmap.c
>
> diff --git a/gcc/unittests/test-bitmap.c b/gcc/unittests/test-bitmap.c
> new file mode 100644
> index 0000000..38adff3
> --- /dev/null
> +++ b/gcc/unittests/test-bitmap.c
So...  We have a long standing issue that we can't iterate on a bitmap 
that is changing.  I can't recall if it's bits going from set to unset 
that causes a problem or vice-versa or both.

There's been talk of putting some sanity checking in the bitmap code to 
detect this error.  A unit testing framework of this nature would be a 
great way to verify that sanity checking worked.

More generally a unit testing framework would allow us to build a suite 
that does a positive test on our sanity checking.  ie, set up the 
invalid state and see if the sanity checking bits complain -- things we 
can't do from a source file.

Anyway, the test itself seems like a reasonable start, we just have to 
settle the framework issues.


Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 03/17] Add test-cfg.c to gcc/unittests
  2015-06-10 15:17 ` [PATCH 03/17] Add test-cfg.c " David Malcolm
@ 2015-06-23 19:26   ` Jeff Law
  2015-06-25 18:13     ` David Malcolm
  0 siblings, 1 reply; 176+ messages in thread
From: Jeff Law @ 2015-06-23 19:26 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 06/10/2015 09:24 AM, David Malcolm wrote:
> gcc/unittests/ChangeLog:
> 	* test-cfg.c: New file.
> ---
>   gcc/unittests/test-cfg.c | 319 +++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 319 insertions(+)
>   create mode 100644 gcc/unittests/test-cfg.c
So this one would be a great place to check that the dominator code does 
something sensible if there's unreachable nodes in the CFG or the 
post-dominator code does something sensible with infinite loops, etc.

I don't necessarily expect you to do this, just pointing it out.

Just a nit, I noticed this included rtl.h, which seems a bit odd.  Are 
those #includes relatively minimal or are they in need to cleanup?

Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH/RFC]: unittesting v2: as a plugin (was Re: [PATCH 00/17] RFC: Addding a unit testing framework to gcc)
  2015-06-17 20:36       ` [PATCH/RFC]: unittesting v2: as a plugin (was Re: [PATCH 00/17] RFC: Addding a unit testing framework to gcc) David Malcolm
@ 2015-06-23 19:29         ` Jeff Law
  2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
  0 siblings, 1 reply; 176+ messages in thread
From: Jeff Law @ 2015-06-23 19:29 UTC (permalink / raw)
  To: David Malcolm, Jakub Jelinek; +Cc: gcc-patches

On 06/17/2015 01:48 PM, David Malcolm wrote:
> On Thu, 2015-06-11 at 00:18 +0200, Jakub Jelinek wrote:
>
> I wrote a custom formatter for the output (class deja_gnu_printer within
> unittests-plugin.c) which generates lines like this on stderr:
>
> PASS: ggc_test.tree_marking
> PASS: ggc_test.custom_struct
> PASS: ggc_test.finalization
> PASS: ggc_test.inheritance
> PASS: ggc_test.chain_next
>
> These get detected on stderr by some new logic inside
> testsuite/lib/prune.exp, which prefixes them with
> [testname-for-summary], and emitting them at the Tcl level, so they end
> up in the .log and .sum files as lines like this:
>
> PASS: c-c++-common/torture/run-unittests-plugin.c   -O0   ggc_test.tree_marking
> PASS: c-c++-common/torture/run-unittests-plugin.c   -O0   ggc_test.custom_struct
> PASS: c-c++-common/torture/run-unittests-plugin.c   -O0   ggc_test.finalization
> PASS: c-c++-common/torture/run-unittests-plugin.c   -O0   ggc_test.inheritance
> PASS: c-c++-common/torture/run-unittests-plugin.c   -O0   ggc_test.chain_next
>
> (if doing it for all testcase output is an issue, perhaps this prune.exp
> logic could be made conditional, so that we only do it for testcases
> using the plugin, or that contain a dg command)
Yea, this is roughly what I was expecting -- you don't have access to 
the .log/.sum files from within the test, so you have to scan the output 
from the test and emit the pass/fail/xfail/whatever messages.

Presumably there's a mechanism for mark expected failures in the gtest 
framework that we can turn into XFAIL/XPASS as needed.  What about the 
UNSUPPORTED result -- perhaps useful if a test depends on some attribute 
of the target.


> This works, and means there's no extra external dependency, and I was
> able to bootstrap with this.  I ran into an issue with "make check": the
> plugin is linked against the previous stage's libstdc++, but "make
> check" doesn't seem to set up LD_LIBRARY_PATH to point at a fresh
> libstdc++ and uses the system copy, leading to
> cc1: error: cannot load plugin ../../unittests_plugin.so
> /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required
> by ../../unittests_plugin.so)
>
> on this Fedora 20 box.  Manually setting LD_LIBRARY_PATH to point at the
> built libstdc++ fixes it.
You might look at the libstdc++ testsuite.  It has to arrange to get the 
just built library used for testing.

Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/17] RFC: Addding a unit testing framework to gcc
  2015-06-10 17:56   ` David Malcolm
  2015-06-10 23:42     ` Jakub Jelinek
  2015-06-23 19:06     ` [PATCH 00/17] RFC: Addding a unit testing framework to gcc Jeff Law
@ 2015-06-23 20:04     ` Mike Stump
  2 siblings, 0 replies; 176+ messages in thread
From: Mike Stump @ 2015-06-23 20:04 UTC (permalink / raw)
  To: David Malcolm; +Cc: Jakub Jelinek, gcc-patches

On Jun 10, 2015, at 10:16 AM, David Malcolm <dmalcolm@redhat.com> wrote:
> It doesn't have an output formatter for the DejaGnu format, but I guess
> I could write one.  The gtest standard output format is IMHO superior to
> DejaGnu's since it tells you start-of-test/end-of-test on separate
> lines, so you can see which test killed things in the event of total
> failure,

dejagnu is superior, total failure isn’t allowed.  We treat it as a bug to be fixed in the framework, not a bug to be fixed in the tool under test.

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 03/17] Add test-cfg.c to gcc/unittests
  2015-06-23 19:26   ` Jeff Law
@ 2015-06-25 18:13     ` David Malcolm
  0 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-06-25 18:13 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches

On Tue, 2015-06-23 at 13:17 -0600, Jeff Law wrote:
> On 06/10/2015 09:24 AM, David Malcolm wrote:
> > gcc/unittests/ChangeLog:
> > 	* test-cfg.c: New file.
> > ---
> >   gcc/unittests/test-cfg.c | 319 +++++++++++++++++++++++++++++++++++++++++++++++
> >   1 file changed, 319 insertions(+)
> >   create mode 100644 gcc/unittests/test-cfg.c
> So this one would be a great place to check that the dominator code does 
> something sensible if there's unreachable nodes in the CFG or the 
> post-dominator code does something sensible with infinite loops, etc.
> 
> I don't necessarily expect you to do this, just pointing it out.
> 
> Just a nit, I noticed this included rtl.h, which seems a bit odd.  Are 
> those #includes relatively minimal or are they in need to cleanup?

Yes, they need to be cleaned up (I #included stuff until it compiled).

My plan is to minimize what these files #include once the more
controversial aspects of this patchkit are resolved - given that the
header files are in a state of flux, any minimization I attempt now is
likely to be out-of-date.


^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 00/16] Unit tests framework (v3)
  2015-06-23 19:29         ` Jeff Law
@ 2015-10-27 19:31           ` David Malcolm
  2015-10-27 19:31             ` [PATCH 11/16] Add test-hash-set.c to unittests David Malcolm
                               ` (18 more replies)
  0 siblings, 19 replies; 176+ messages in thread
From: David Malcolm @ 2015-10-27 19:31 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

This is a followup to these proposals:
 * v1: https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00765.html
 * v2: https://gcc.gnu.org/ml/gcc-patches/2015-06/msg01224.html

The following patch kit adds a unit tests framework for gcc,
as a new subdirectory below gcc/testsuite.

The aim is to give us direct coverage of low level implementation
details that aren't well covered by our existing tests, such as
our data structures, gengtype, etc.  This will let us have tests
that directly poke at specific internal APIs and verify that the
right thing happens, rather than having to write source code and
option combinations that we hope touches the relevant state.
It should make it trivial to add new unit tests.

I see it as complementary to our existing test approaches.

Like previous versions of the patch kit it uses the Google Test
framework, since I've had good experiences with it:
  http://code.google.com/p/googletest/
and like v2 of the kit it embeds a two-file copy of v1.7 of
the kit, to avoid adding extra dependencies (one .h file and one
.c file).

v1 of the kit was structured as a frontend, v2 of the kit as
a plugin that was built as if it were a frontend.  Both of
these approaches were problematic, so this version
of the patch kit simply builds as a test case within the
plugin.exp suites.

In this approach, each of gcc.dg and g++.dg have a plugin.exp that
lists plugins to be built and source files to then compile with
the plugin.  This patch kit inserts into them references to the plugin
within ../../unittests, so that we can run the tests within both cc1
and cc1plus without having to list everything twice.  The plugin
is built by plugin.exp and plugin-support.exp as per the existing
test cases.  Doing so requires #include-ing everything relevant
within unittests-plugin.c.

The plugin uses a custom gtest reporter that reports results in
DejaGnu format.  The kit adds some logic to testsuite/lib/prune.exp
to parse the DejaGnu output on stderr e.g.:
  PASS: ggc_test.inheritance
and re-emits it at the Tcl level, so that the unit test results from
the plugin are reported within the regular test output like this:
  PASS: gcc.dg/plugin/unittests.c -fplugin=./unittests-plugin.so  ggc_test.inheritance

Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu
(on top of r229364); adds 61 new PASS results to each of gcc.sum and
g++.sum.

I've broken up the patches into logical chunks in the hope of making
review easier, but this is effectively one change, and would be
committed as such.  Though if any individual testcases are
problematic, they could be deferred, if that will help get the rest
of the work approved.

[There are some FIXMEs in the testcases indicating room for further
testing, and I've not fully reduced the #includes in them; is the
"blessed" #include order documented yet, and do we have tooling
in "contrib" for this yet?]

With those caveats, OK for trunk?

David Malcolm (16):
  Add unittest infrastructure
  Add embedded copy of gtest-1.7 to unittests
  Add test-bitmap.c to unittests
  Add test-cfg.c to unittests
  Add test-et-forest.c to unittests
  Add test-folding.c to unittests
  Add test-functions.c to unittests
  Add test-ggc.c to unittests
  Add test-gimple.c to unittests
  Add test-hash-map.c to unittests
  Add test-hash-set.c to unittests
  Add test-locations.c to unittests
  Add test-rtl.c to unittests
  Add test-tree.c to unittests
  Add test-vec.c to unittests
  Add test-wide-int.c to unittests

 gcc/testsuite/g++.dg/plugin/plugin.exp     |     4 +-
 gcc/testsuite/g++.dg/plugin/unittests.C    |     9 +
 gcc/testsuite/gcc.dg/plugin/plugin.exp     |     1 +
 gcc/testsuite/gcc.dg/plugin/unittests.c    |     9 +
 gcc/testsuite/lib/plugin-support.exp       |    29 +-
 gcc/testsuite/lib/prune.exp                |    43 +
 gcc/testsuite/unittests/gtest-all.c        |  9592 +++++++++++++
 gcc/testsuite/unittests/gtest/gtest.h      | 20061 +++++++++++++++++++++++++++
 gcc/testsuite/unittests/test-bitmap.c      |   116 +
 gcc/testsuite/unittests/test-cfg.c         |   319 +
 gcc/testsuite/unittests/test-et-forest.c   |   121 +
 gcc/testsuite/unittests/test-folding.c     |   120 +
 gcc/testsuite/unittests/test-functions.c   |   645 +
 gcc/testsuite/unittests/test-ggc.c         |   299 +
 gcc/testsuite/unittests/test-gimple.c      |   178 +
 gcc/testsuite/unittests/test-hash-map.c    |    77 +
 gcc/testsuite/unittests/test-hash-set.c    |    53 +
 gcc/testsuite/unittests/test-locations.c   |   145 +
 gcc/testsuite/unittests/test-rtl.c         |    94 +
 gcc/testsuite/unittests/test-tree.c        |   101 +
 gcc/testsuite/unittests/test-vec.c         |   161 +
 gcc/testsuite/unittests/test-wide-int.c    |   185 +
 gcc/testsuite/unittests/unittests-plugin.c |   213 +
 23 files changed, 32573 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/plugin/unittests.C
 create mode 100644 gcc/testsuite/gcc.dg/plugin/unittests.c
 create mode 100644 gcc/testsuite/unittests/gtest-all.c
 create mode 100644 gcc/testsuite/unittests/gtest/gtest.h
 create mode 100644 gcc/testsuite/unittests/test-bitmap.c
 create mode 100644 gcc/testsuite/unittests/test-cfg.c
 create mode 100644 gcc/testsuite/unittests/test-et-forest.c
 create mode 100644 gcc/testsuite/unittests/test-folding.c
 create mode 100644 gcc/testsuite/unittests/test-functions.c
 create mode 100644 gcc/testsuite/unittests/test-ggc.c
 create mode 100644 gcc/testsuite/unittests/test-gimple.c
 create mode 100644 gcc/testsuite/unittests/test-hash-map.c
 create mode 100644 gcc/testsuite/unittests/test-hash-set.c
 create mode 100644 gcc/testsuite/unittests/test-locations.c
 create mode 100644 gcc/testsuite/unittests/test-rtl.c
 create mode 100644 gcc/testsuite/unittests/test-tree.c
 create mode 100644 gcc/testsuite/unittests/test-vec.c
 create mode 100644 gcc/testsuite/unittests/test-wide-int.c
 create mode 100644 gcc/testsuite/unittests/unittests-plugin.c

-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 15/16] Add test-vec.c to unittests
  2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
  2015-10-27 19:31             ` [PATCH 11/16] Add test-hash-set.c to unittests David Malcolm
  2015-10-27 19:31             ` [PATCH 05/16] Add test-et-forest.c " David Malcolm
@ 2015-10-27 19:31             ` David Malcolm
  2015-10-30  5:10               ` Jeff Law
  2015-10-27 19:31             ` [PATCH 03/16] Add test-bitmap.c " David Malcolm
                               ` (15 subsequent siblings)
  18 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-10-27 19:31 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/testsuite/ChangeLog:
	* unittests/test-vec.c: New file.
---
 gcc/testsuite/unittests/test-vec.c | 161 +++++++++++++++++++++++++++++++++++++
 1 file changed, 161 insertions(+)
 create mode 100644 gcc/testsuite/unittests/test-vec.c

diff --git a/gcc/testsuite/unittests/test-vec.c b/gcc/testsuite/unittests/test-vec.c
new file mode 100644
index 0000000..c5b9d78
--- /dev/null
+++ b/gcc/testsuite/unittests/test-vec.c
@@ -0,0 +1,161 @@
+/* Unit tests for vec<>.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "gtest/gtest.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "vec.h"
+
+namespace {
+
+class vec_test : public ::testing::Test
+{
+ protected:
+  /* Add the range [START..LIMIT) to V.  */
+  void
+  safe_push_range (vec <int>&v, int start, int limit)
+  {
+    for (int i = start; i < limit; i++)
+      v.safe_push (i);
+  }
+};
+
+TEST_F (vec_test, quick_push)
+{
+  auto_vec <int> v;
+  EXPECT_EQ (0, v.length ());
+  v.reserve (3);
+  EXPECT_EQ (0, v.length ());
+  EXPECT_TRUE (v.space (3));
+  v.quick_push (5);
+  v.quick_push (6);
+  v.quick_push (7);
+  EXPECT_EQ (3, v.length ());
+  EXPECT_EQ (5, v[0]);
+  EXPECT_EQ (6, v[1]);
+  EXPECT_EQ (7, v[2]);
+}
+
+TEST_F (vec_test, safe_push)
+{
+  auto_vec <int> v;
+  EXPECT_EQ (0, v.length ());
+  v.safe_push (5);
+  v.safe_push (6);
+  v.safe_push (7);
+  EXPECT_EQ (3, v.length ());
+  EXPECT_EQ (5, v[0]);
+  EXPECT_EQ (6, v[1]);
+  EXPECT_EQ (7, v[2]);
+}
+
+TEST_F (vec_test, truncate)
+{
+  auto_vec <int> v;
+  EXPECT_EQ (0, v.length ());
+  safe_push_range (v, 0, 10);
+  EXPECT_EQ (10, v.length ());
+
+  v.truncate (5);
+  EXPECT_EQ (5, v.length ());
+}
+
+TEST_F (vec_test, safe_grow_cleared)
+{
+  auto_vec <int> v;
+  EXPECT_EQ (0, v.length ());
+  v.safe_grow_cleared (50);
+  EXPECT_EQ (50, v.length ());
+  EXPECT_EQ (0, v[0]);
+  EXPECT_EQ (0, v[49]);
+}
+
+TEST_F (vec_test, pop)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 5, 20);
+  EXPECT_EQ (15, v.length ());
+
+  int last = v.pop ();
+  EXPECT_EQ (19, last);
+  EXPECT_EQ (14, v.length ());
+}
+
+TEST_F (vec_test, safe_insert)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.safe_insert (5, 42);
+  EXPECT_EQ (4, v[4]);
+  EXPECT_EQ (42, v[5]);
+  EXPECT_EQ (5, v[6]);
+  EXPECT_EQ (11, v.length ());
+}
+
+TEST_F (vec_test, ordered_remove)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.ordered_remove (5);
+  EXPECT_EQ (4, v[4]);
+  EXPECT_EQ (6, v[5]);
+  EXPECT_EQ (9, v.length ());
+}
+
+TEST_F (vec_test, unordered_remove)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.unordered_remove (5);
+  EXPECT_EQ (9, v.length ());
+}
+
+TEST_F (vec_test, block_remove)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.block_remove (5, 3);
+  EXPECT_EQ (3, v[3]);
+  EXPECT_EQ (4, v[4]);
+  EXPECT_EQ (8, v[5]);
+  EXPECT_EQ (9, v[6]);
+  EXPECT_EQ (7, v.length ());
+}
+
+static int reverse_cmp (const void *p_i, const void *p_j)
+{
+  return *(const int *)p_j - *(const int *)p_i;
+}
+
+TEST_F (vec_test, qsort)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.qsort (reverse_cmp);
+  EXPECT_EQ (9, v[0]);
+  EXPECT_EQ (8, v[1]);
+  EXPECT_EQ (1, v[8]);
+  EXPECT_EQ (0, v[9]);
+  EXPECT_EQ (10, v.length ());
+}
+
+}  // anon namespace
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 11/16] Add test-hash-set.c to unittests
  2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
@ 2015-10-27 19:31             ` David Malcolm
  2015-10-30  4:54               ` Jeff Law
  2015-10-27 19:31             ` [PATCH 05/16] Add test-et-forest.c " David Malcolm
                               ` (17 subsequent siblings)
  18 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-10-27 19:31 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/testsuite/ChangeLog:
	* unittests/test-hash-set.c: New file.
---
 gcc/testsuite/unittests/test-hash-set.c | 53 +++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 gcc/testsuite/unittests/test-hash-set.c

diff --git a/gcc/testsuite/unittests/test-hash-set.c b/gcc/testsuite/unittests/test-hash-set.c
new file mode 100644
index 0000000..b38874b
--- /dev/null
+++ b/gcc/testsuite/unittests/test-hash-set.c
@@ -0,0 +1,53 @@
+/* Unit tests for hash-set.h.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "gtest/gtest.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+
+namespace {
+
+TEST (hash_set_test, set_of_strings)
+{
+  hash_set <const char *> s;
+  EXPECT_EQ (0, s.elements ());
+
+  const char *red = "red";
+  const char *green = "green";
+  const char *blue = "blue";
+
+  EXPECT_EQ (false, s.contains (red));
+
+  /* Populate the hash_set.  */
+  EXPECT_EQ (false, s.add (red));
+  EXPECT_EQ (false, s.add (green));
+  EXPECT_EQ (false, s.add (blue));
+
+  /* Verify that the values are now within the set.  */
+  EXPECT_EQ (true, s.contains (red));
+  EXPECT_EQ (true, s.contains (green));
+  EXPECT_EQ (true, s.contains (blue));
+}
+
+}  /* anon namespace.  */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 05/16] Add test-et-forest.c to unittests
  2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
  2015-10-27 19:31             ` [PATCH 11/16] Add test-hash-set.c to unittests David Malcolm
@ 2015-10-27 19:31             ` David Malcolm
  2015-10-30  4:11               ` Jeff Law
  2015-10-27 19:31             ` [PATCH 15/16] Add test-vec.c " David Malcolm
                               ` (16 subsequent siblings)
  18 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-10-27 19:31 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/testsuite/ChangeLog:
	* unittests/test-et-forest.c: New file.
---
 gcc/testsuite/unittests/test-et-forest.c | 121 +++++++++++++++++++++++++++++++
 1 file changed, 121 insertions(+)
 create mode 100644 gcc/testsuite/unittests/test-et-forest.c

diff --git a/gcc/testsuite/unittests/test-et-forest.c b/gcc/testsuite/unittests/test-et-forest.c
new file mode 100644
index 0000000..35ca084
--- /dev/null
+++ b/gcc/testsuite/unittests/test-et-forest.c
@@ -0,0 +1,121 @@
+/* Unit tests for et-forest.h
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "gtest/gtest.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "alloc-pool.h"
+#include "et-forest.h"
+
+namespace {
+
+TEST (et_forest_test, single_node)
+{
+  void *test_data = (void *)0xcafebabe;
+
+  et_node *n = et_new_tree (test_data);
+  EXPECT_EQ (n->data, test_data);
+  EXPECT_EQ (n, et_root (n));
+  et_free_tree (n);
+}
+
+/* Test of this tree:
+       a
+      / \
+     /   \
+    b     c
+   / \    |
+  d   e   f.  */
+
+TEST (et_forest_test, simple_tree)
+{
+  et_node *a = et_new_tree (NULL);
+  et_node *b = et_new_tree (NULL);
+  et_node *c = et_new_tree (NULL);
+  et_node *d = et_new_tree (NULL);
+  et_node *e = et_new_tree (NULL);
+  et_node *f = et_new_tree (NULL);
+
+  et_set_father (b, a);
+  et_set_father (c, a);
+  et_set_father (d, b);
+  et_set_father (e, b);
+  et_set_father (f, c);
+
+  EXPECT_TRUE (et_below (a, a));
+  EXPECT_TRUE (et_below (b, a));
+  EXPECT_TRUE (et_below (c, a));
+  EXPECT_TRUE (et_below (d, a));
+  EXPECT_TRUE (et_below (e, a));
+  EXPECT_TRUE (et_below (f, a));
+
+  EXPECT_FALSE (et_below (a, b));
+  EXPECT_TRUE (et_below (b, b));
+  EXPECT_FALSE (et_below (c, b));
+  EXPECT_TRUE (et_below (d, b));
+  EXPECT_TRUE (et_below (e, b));
+  EXPECT_FALSE (et_below (f, b));
+
+  EXPECT_FALSE (et_below (a, c));
+  EXPECT_FALSE (et_below (b, c));
+  EXPECT_TRUE (et_below (c, c));
+  EXPECT_FALSE (et_below (d, c));
+  EXPECT_FALSE (et_below (e, c));
+  EXPECT_TRUE (et_below (f, c));
+
+  EXPECT_FALSE (et_below (a, d));
+  EXPECT_FALSE (et_below (b, d));
+  EXPECT_FALSE (et_below (c, d));
+  EXPECT_TRUE (et_below (d, d));
+  EXPECT_FALSE (et_below (e, d));
+  EXPECT_FALSE (et_below (f, d));
+
+  EXPECT_FALSE (et_below (a, e));
+  EXPECT_FALSE (et_below (b, e));
+  EXPECT_FALSE (et_below (c, e));
+  EXPECT_FALSE (et_below (d, e));
+  EXPECT_TRUE (et_below (e, e));
+  EXPECT_FALSE (et_below (f, e));
+
+  EXPECT_FALSE (et_below (a, f));
+  EXPECT_FALSE (et_below (b, f));
+  EXPECT_FALSE (et_below (c, f));
+  EXPECT_FALSE (et_below (d, f));
+  EXPECT_FALSE (et_below (e, f));
+  EXPECT_TRUE (et_below (f, f));
+
+  et_free_tree_force (a);
+}
+
+TEST (et_forest_test, disconnected_nodes)
+{
+  et_node *a = et_new_tree (NULL);
+  et_node *b = et_new_tree (NULL);
+
+  EXPECT_FALSE (et_below (a, b));
+  EXPECT_FALSE (et_below (b, a));
+
+  et_free_tree (a);
+  et_free_tree (b);
+}
+
+}  // anon namespace
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 03/16] Add test-bitmap.c to unittests
  2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
                               ` (2 preceding siblings ...)
  2015-10-27 19:31             ` [PATCH 15/16] Add test-vec.c " David Malcolm
@ 2015-10-27 19:31             ` David Malcolm
  2015-10-29 21:36               ` Jeff Law
  2015-10-27 19:31             ` [PATCH 01/16] Add unittest infrastructure David Malcolm
                               ` (14 subsequent siblings)
  18 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-10-27 19:31 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/testsuite/ChangeLog:
	* unittests/test-bitmap.c: New file.
---
 gcc/testsuite/unittests/test-bitmap.c | 116 ++++++++++++++++++++++++++++++++++
 1 file changed, 116 insertions(+)
 create mode 100644 gcc/testsuite/unittests/test-bitmap.c

diff --git a/gcc/testsuite/unittests/test-bitmap.c b/gcc/testsuite/unittests/test-bitmap.c
new file mode 100644
index 0000000..1f8bbb2
--- /dev/null
+++ b/gcc/testsuite/unittests/test-bitmap.c
@@ -0,0 +1,116 @@
+/* Unit tests for GCC's bitmap-handling.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "gtest/gtest.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "bitmap.h"
+
+namespace {
+
+/* Freshly-created bitmaps ought to be empty.  */
+
+TEST (bitmap_test, gc_alloc)
+{
+  bitmap b = bitmap_gc_alloc ();
+  EXPECT_TRUE (bitmap_empty_p (b));
+}
+
+/* Verify bitmap_set_range.  */
+
+TEST (bitmap_test, set_range)
+{
+  bitmap b = bitmap_gc_alloc ();
+  EXPECT_TRUE (bitmap_empty_p (b));
+
+  bitmap_set_range (b, 7, 5);
+  EXPECT_FALSE (bitmap_empty_p (b));
+  EXPECT_EQ (5, bitmap_count_bits (b));
+
+  /* Verify bitmap_bit_p at the boundaries.  */
+  EXPECT_FALSE (bitmap_bit_p (b, 6));
+  EXPECT_TRUE (bitmap_bit_p (b, 7));
+  EXPECT_TRUE (bitmap_bit_p (b, 11));
+  EXPECT_FALSE (bitmap_bit_p (b, 12));
+}
+
+/* Verify splitting a range into two pieces using bitmap_clear_bit.  */
+
+TEST (bitmap_test, clear_bit_in_middle)
+{
+  bitmap b = bitmap_gc_alloc ();
+
+  /* Set b to [100..200].  */
+  bitmap_set_range (b, 100, 100);
+  EXPECT_EQ (100, bitmap_count_bits (b));
+
+  /* Clear a bit in the middle.  */
+  bool changed = bitmap_clear_bit (b, 150);
+  EXPECT_TRUE (changed);
+  EXPECT_EQ (99, bitmap_count_bits (b));
+  EXPECT_TRUE (bitmap_bit_p (b, 149));
+  EXPECT_FALSE (bitmap_bit_p (b, 150));
+  EXPECT_TRUE (bitmap_bit_p (b, 151));
+}
+
+/* Verify bitmap_copy.  */
+
+TEST (bitmap_test, copying)
+{
+  bitmap src = bitmap_gc_alloc ();
+  bitmap_set_range (src, 40, 10);
+
+  bitmap dst = bitmap_gc_alloc ();
+  EXPECT_FALSE (bitmap_equal_p (src, dst));
+  bitmap_copy (dst, src);
+  EXPECT_TRUE (bitmap_equal_p (src, dst));
+
+  /* Verify that we can make them unequal again...  */
+  bitmap_set_range (src, 70, 5);
+  EXPECT_FALSE (bitmap_equal_p (src, dst));
+
+  /* ...and that changing src after the copy didn't affect
+     the other: */
+  EXPECT_FALSE (bitmap_bit_p (dst, 70));
+}
+
+/* Verify bitmap_single_bit_set_p.  */
+TEST (bitmap_test, bitmap_single_bit_set_p)
+{
+  bitmap b = bitmap_gc_alloc ();
+
+  EXPECT_FALSE (bitmap_single_bit_set_p (b));
+
+  bitmap_set_range (b, 42, 1);
+  EXPECT_TRUE (bitmap_single_bit_set_p (b));
+  EXPECT_EQ (42, bitmap_first_set_bit (b));
+
+  bitmap_set_range (b, 1066, 1);
+  EXPECT_FALSE (bitmap_single_bit_set_p (b));
+  EXPECT_EQ (42, bitmap_first_set_bit (b));
+
+  bitmap_clear_range (b, 0, 100);
+  EXPECT_TRUE (bitmap_single_bit_set_p (b));
+  EXPECT_EQ (1066, bitmap_first_set_bit (b));
+}
+
+}  // anon namespace
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 01/16] Add unittest infrastructure
  2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
                               ` (3 preceding siblings ...)
  2015-10-27 19:31             ` [PATCH 03/16] Add test-bitmap.c " David Malcolm
@ 2015-10-27 19:31             ` David Malcolm
  2015-10-30  5:20               ` Jeff Law
  2015-10-27 19:32             ` [PATCH 04/16] Add test-cfg.c to unittests David Malcolm
                               ` (13 subsequent siblings)
  18 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-10-27 19:31 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/testsuite/ChangeLog:
	* g++.dg/plugin/plugin.exp (plugin_test_list): Add the unittests
	plugin.
	* g++.dg/plugin/unittests.C: New file.
	* gcc.dg/plugin/plugin.exp (plugin_test_list): Add the unittests
	plugin.
	* gcc.dg/plugin/unittests.c: New file.
	* lib/plugin-support.exp (dg-plugin-run-gengtype): New function.
	(plugin-get-options): Handle dg-plugin-run-gengtype.
	* lib/prune.exp (prune_gcc_output): Process any DejaGnu output
	from the test, and convert into results at this level, prefixing
	with the testcase.
	* unittests/unittests-plugin.c: New file.
---
 gcc/testsuite/g++.dg/plugin/plugin.exp     |   4 +-
 gcc/testsuite/g++.dg/plugin/unittests.C    |   9 ++
 gcc/testsuite/gcc.dg/plugin/plugin.exp     |   1 +
 gcc/testsuite/gcc.dg/plugin/unittests.c    |   9 ++
 gcc/testsuite/lib/plugin-support.exp       |  29 +++-
 gcc/testsuite/lib/prune.exp                |  43 ++++++
 gcc/testsuite/unittests/unittests-plugin.c | 213 +++++++++++++++++++++++++++++
 7 files changed, 306 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/plugin/unittests.C
 create mode 100644 gcc/testsuite/gcc.dg/plugin/unittests.c
 create mode 100644 gcc/testsuite/unittests/unittests-plugin.c

diff --git a/gcc/testsuite/g++.dg/plugin/plugin.exp b/gcc/testsuite/g++.dg/plugin/plugin.exp
index 3ed1397..3e6e7f1 100644
--- a/gcc/testsuite/g++.dg/plugin/plugin.exp
+++ b/gcc/testsuite/g++.dg/plugin/plugin.exp
@@ -62,7 +62,9 @@ set plugin_test_list [list \
     { dumb_plugin.c dumb-plugin-test-1.C } \
     { header_plugin.c header-plugin-test.C } \
     { decl_plugin.c decl-plugin-test.C } \
-    { def_plugin.c def-plugin-test.C } ]
+    { def_plugin.c def-plugin-test.C } \
+    { ../../unittests/unittests-plugin.c unittests.C } \
+]
 
 foreach plugin_test $plugin_test_list {
     # Replace each source file with its full-path name
diff --git a/gcc/testsuite/g++.dg/plugin/unittests.C b/gcc/testsuite/g++.dg/plugin/unittests.C
new file mode 100644
index 0000000..42b4e93
--- /dev/null
+++ b/gcc/testsuite/g++.dg/plugin/unittests.C
@@ -0,0 +1,9 @@
+/* Placeholder C++ source file for running the unittests plugin.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+int
+main (int argc, char **argv)
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp
index 39fab6e..5956fe3 100644
--- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
+++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
@@ -63,6 +63,7 @@ set plugin_test_list [list \
     { start_unit_plugin.c start_unit-test-1.c } \
     { finish_unit_plugin.c finish_unit-test-1.c } \
     { wide-int_plugin.c wide-int-test-1.c } \
+    { ../../unittests/unittests-plugin.c unittests.c } \
 ]
 
 foreach plugin_test $plugin_test_list {
diff --git a/gcc/testsuite/gcc.dg/plugin/unittests.c b/gcc/testsuite/gcc.dg/plugin/unittests.c
new file mode 100644
index 0000000..610e91d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/unittests.c
@@ -0,0 +1,9 @@
+/* Placeholder C source file for running the unittests plugin.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+int
+main (int argc, char **argv)
+{
+  return 0;
+}
diff --git a/gcc/testsuite/lib/plugin-support.exp b/gcc/testsuite/lib/plugin-support.exp
index a9343cb..ffa8404 100644
--- a/gcc/testsuite/lib/plugin-support.exp
+++ b/gcc/testsuite/lib/plugin-support.exp
@@ -20,6 +20,32 @@
 load_lib dg.exp
 load_lib gcc.exp
 
+# Special-case directive for use by unittests/unittests-plugin.c
+# for invoking gengtype on test-ggc.c, to generate a
+# gt-unittests-test-ggc.h file.
+
+proc dg-plugin-run-gengtype { args } {
+    global srcdir objdir
+    verbose "dg-plugin-run-gengtype: args: $args" 3
+    verbose "srcdir: $srcdir" 3
+    verbose "objdir: $objdir" 3
+    set gcc_objdir "$objdir/../.."
+    set gengtype_cmd \
+	"$gcc_objdir/gengtype \
+          --plugin gt-unittests-test-ggc.h \
+          --read-state $gcc_objdir/gtype.state \
+          $srcdir/unittests/test-ggc.c"
+    verbose "gengtype_cmd: $gengtype_cmd" 3
+
+    set status [remote_exec build $gengtype_cmd]
+    set status [lindex $status 0]
+    if { $status != 0 } then {
+	fail "gengtype"
+    } else {
+	pass "gengtype"
+    }
+}
+
 #
 # plugin-get-options -- process test directives
 #
@@ -35,7 +61,8 @@ proc plugin-get-options { src } {
     set tmp [dg-get-options $src]
     foreach op $tmp {
 	set cmd [lindex $op 0]
-	if { ![string compare "dg-options" $cmd] } {
+	if { ![string compare "dg-options" $cmd]
+	     || ![string compare "dg-plugin-run-gengtype" $cmd] } {
 	    set status [catch "$op" errmsg]
 	    if { $status != 0 } {
 		perror "src: $errmsg for \"$op\"\n"
diff --git a/gcc/testsuite/lib/prune.exp b/gcc/testsuite/lib/prune.exp
index fa10043..40a5a05 100644
--- a/gcc/testsuite/lib/prune.exp
+++ b/gcc/testsuite/lib/prune.exp
@@ -73,6 +73,49 @@ proc prune_gcc_output { text } {
     # Call into multiline.exp to handle any multiline output directives.
     set text [handle-multiline-outputs $text]
 
+    # Process any DejaGnu output from the test, and convert into results at
+    # this level, prefixing with the testcase.
+    # For example, given the line
+    #   PASS: vec_test.quick_push
+    # from the test, we want to call "pass", giving a line like this in
+    # our .log/.sum, depending on [testname-for-summary]:
+    #   PASS: gcc.dg/plugin/unittests.c -fplugin=./unittests-plugin.so  vec_test.quick_push
+    verbose "Would handle: $text\n"
+    # Currently this only covers the possible outputs from
+    # unittests-plugin.c (PASS/FAIL/NOTE).
+    foreach status_pair { {"PASS" pass} {"FAIL" fail} {"NOTE" note} } {
+	set kind [lindex $status_pair 0]
+	set handler [lindex $status_pair 1]
+	#verbose "kind: $kind   handler: $handler"
+	set pattern "^$kind: (.*?)$"
+	#verbose "pattern: $pattern"
+	set matches [regexp -all -inline -lineanchor $pattern $text]
+	#verbose "matches: $matches"
+	foreach {matched_line detail} $matches {
+	    #verbose "matched_line: $matched_line"
+	    #verbose "detail: $detail"
+	    set testname [testname-for-summary]
+
+	    # Call the handler ("pass"/"fail" etc) to convert to a message
+	    # at this level, prefixed with [testname-for-summary]:
+	    $handler "$testname $detail"
+
+	    # Prune $matched_line from $text (or, at least, the first
+	    # instance of it).
+	    # Is there a less clunky way to do this?  (regsub would require
+	    # escaping any regex special characters within $matched_line).
+	    # Locate first instance of matched_line:
+	    set idx [string first $matched_line $text]
+	    # Get length, adding one for the trailing newline char:
+	    set linelen [expr [string length $matched_line] + 1]
+	    # Cut it out from the middle of $text:
+	    set textlen [string length $text]
+	    set before [string range $text 0 [expr $idx - 1] ]
+	    set after_ [string range $text [expr $idx + $linelen] $textlen]
+	    set text $before$after_
+	}
+    }
+
     #send_user "After:$text\n"
 
     return $text
diff --git a/gcc/testsuite/unittests/unittests-plugin.c b/gcc/testsuite/unittests/unittests-plugin.c
new file mode 100644
index 0000000..e0fdf76
--- /dev/null
+++ b/gcc/testsuite/unittests/unittests-plugin.c
@@ -0,0 +1,213 @@
+/* Unittests plugin.  */
+
+/* The following options are needed by gtest.
+
+  { dg-options "-lpthread -fPIC -Wno-missing-field-initializers -Wno-conversion-null -Wno-suggest-attribute=format -Wno-sign-compare" }  */
+
+/* Directive to invoke gengtype on test-ggc.c
+   (handled by plugin-support.exp).
+
+   { dg-plugin-run-gengtype "" } */
+
+#include "config.h"
+#include "gtest/gtest.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "tm.h"
+#include "toplev.h"
+#include "hash-table.h"
+#include "vec.h"
+#include "ggc.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "tree-eh.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "intl.h"
+#include "context.h"
+#include "diagnostic.h"
+#include "bitmap.h"
+
+int plugin_is_GPL_compatible;
+
+/* Print test output in DejaGnu form.  */
+class deja_gnu_printer : public ::testing::EmptyTestEventListener
+{
+ public:
+  deja_gnu_printer (FILE *outfile, int verbose)
+    : m_outfile (outfile),
+      m_verbose (verbose)
+  {}
+
+ private:
+  virtual void
+  OnTestCaseStart(const ::testing::TestCase& test_case)
+  {
+    if (m_verbose)
+      fprintf (m_outfile, "NOTE: %s: case starting\n",
+	       test_case.name ());
+  }
+
+  /* Vfunc called before a test starts.  */
+  virtual void
+  OnTestStart (const ::testing::TestInfo& test_info)
+  {
+    if (m_verbose)
+      fprintf (m_outfile,
+	       "NOTE: %s.%s: test starting\n",
+	       test_info.test_case_name (), test_info.name ());
+    m_per_test_fails = 0;
+  }
+
+  /* Vfunc called after a failed assertion or a SUCCEED() invocation.  */
+  virtual void
+  OnTestPartResult (const ::testing::TestPartResult& test_part_result)
+  {
+    fprintf (m_outfile,
+	     "%s: %s:%d: %s\n",
+	     test_part_result.failed () ? "FAIL" : "PASS",
+	     test_part_result.file_name (),
+	     test_part_result.line_number (),
+	     test_part_result.summary ());
+    if (test_part_result.failed ())
+      m_per_test_fails++;
+  }
+
+  /* Vfunc called after a test ends.  */
+  virtual void
+  OnTestEnd (const ::testing::TestInfo& test_info)
+  {
+    if (m_verbose)
+      fprintf (m_outfile,
+	       "NOTE: %s.%s: test ending: %i failure(s)\n",
+	       test_info.test_case_name (), test_info.name (),
+	       m_per_test_fails);
+    fprintf (m_outfile,
+	     "%s: %s.%s\n",
+	     m_per_test_fails > 0 ? "FAIL" : "PASS",
+	     test_info.test_case_name (), test_info.name ());
+  }
+
+  virtual void
+  OnTestCaseEnd (const ::testing::TestCase& test_case)
+  {
+    if (m_verbose)
+      fprintf (m_outfile, "NOTE: %s: case ending\n",
+	       test_case.name ());
+  }
+
+ private:
+    FILE *m_outfile;
+    int m_verbose;
+    int m_per_test_fails;
+};
+
+/* Get rid of the default gtest result printer, and instead use LISTENER,
+   taking ownership of the ptr.  */
+
+static void
+replace_default_gtest_result_printer (::testing::TestEventListener *listener)
+{
+  ::testing::TestEventListeners& listeners =
+    ::testing::UnitTest::GetInstance()->listeners();
+  delete listeners.Release(listeners.default_result_printer());
+  listeners.Append(listener);
+}
+
+/* Callback handler for the PLUGIN_FINISH event.
+   At this point, all GCC subsystems should be initialized and
+   "warmed up"; this is where we run our unit tests.  */
+
+static void
+on_finish (void */*gcc_data*/, void */*user_data*/)
+{
+  /* Initialize gtest with empty arguments.  In theory we could locate
+     the arguments passed to the plugin and pass them on to gtest. */
+  int argc = 0;
+  char **argv = NULL;
+  ::testing::InitGoogleTest (&argc, argv);
+
+  /* Use our custom result-printer.  */
+  replace_default_gtest_result_printer (new deja_gnu_printer (stderr, 0));
+
+  /* Reset some state.  */
+  input_location = UNKNOWN_LOCATION;
+  bitmap_obstack_initialize (NULL);
+
+  /* Run the tests.  */
+  int result = RUN_ALL_TESTS();
+
+  /* Ensure that a test failure leads to the process exiting with
+     a non-zero exit code.  */
+  if (result)
+    error ("at least one test failure occurred");
+
+  /* Cleanup.  */
+  bitmap_obstack_release (NULL);
+}
+
+/* Defined in "gt-unittests-test-ggc.h", as generated by
+   dg-plugin-run-gengtype.  */
+extern const struct ggc_root_tab gt_ggc_r_gt_unittests_test_ggc_h[];
+#if 0
+extern const struct ggc_root_tab gt_ggc_rd_gt_unittests_test_ggc_h[];
+#endif
+
+int
+plugin_init (struct plugin_name_args *plugin_info,
+	     struct plugin_gcc_version */*version*/)
+{
+  if (0)
+    fprintf (stderr, "got here\n");
+
+  register_callback (plugin_info->base_name,
+		     PLUGIN_REGISTER_GGC_ROOTS,
+		     NULL,
+		     const_cast <ggc_root_tab *> (
+		       gt_ggc_r_gt_unittests_test_ggc_h));
+
+  /* FIXME: we'd use this for test-ggc.c's test_of_deletable.
+     However we'd need to register it as a different kind of roottab;
+     doing it with PLUGIN_REGISTER_GGC_ROOTS leads to a segfault on
+     collection due to the NULL cb.
+     It looks like we need another hook; gt_ggc_deletable_rtab is
+     currently not expandable.  */
+#if 0
+  register_callback (plugin_info->base_name,
+		     PLUGIN_REGISTER_GGC_ROOTS,
+		     NULL,
+		     const_cast <ggc_root_tab *> (
+		       gt_ggc_rd_gt_unittests_test_ggc_h));
+#endif
+  register_callback (plugin_info->base_name,
+		     PLUGIN_FINISH,
+		     on_finish,
+		     NULL); /* void *user_data */
+
+  return 0;
+}
+
+/* Include gtest's source.  */
+#include "gtest-all.c"
+
+/* Now include the test cases.  */
+#include "test-bitmap.c"
+#include "test-cfg.c"
+#include "test-et-forest.c"
+#include "test-folding.c"
+#include "test-functions.c"
+#include "test-ggc.c"
+#include "test-gimple.c"
+#include "test-hash-map.c"
+#include "test-hash-set.c"
+#include "test-locations.c"
+#include "test-rtl.c"
+#include "test-tree.c"
+#include "test-vec.c"
+#include "test-wide-int.c"
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 10/16] Add test-hash-map.c to unittests
  2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
                               ` (5 preceding siblings ...)
  2015-10-27 19:32             ` [PATCH 04/16] Add test-cfg.c to unittests David Malcolm
@ 2015-10-27 19:32             ` David Malcolm
  2015-10-30  4:57               ` Jeff Law
  2015-10-27 19:32             ` [PATCH 07/16] Add test-functions.c " David Malcolm
                               ` (11 subsequent siblings)
  18 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-10-27 19:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/testsuite/ChangeLog:
	* unittests/test-hash-map.c: New file.
---
 gcc/testsuite/unittests/test-hash-map.c | 77 +++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)
 create mode 100644 gcc/testsuite/unittests/test-hash-map.c

diff --git a/gcc/testsuite/unittests/test-hash-map.c b/gcc/testsuite/unittests/test-hash-map.c
new file mode 100644
index 0000000..3198bca
--- /dev/null
+++ b/gcc/testsuite/unittests/test-hash-map.c
@@ -0,0 +1,77 @@
+/* Unit tests for hash-map.h.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "gtest/gtest.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+
+namespace {
+
+TEST (hash_map_test, map_of_strings_to_int)
+{
+  hash_map <const char *, int> m;
+
+  const char *ostrich = "ostrich";
+  const char *elephant = "elephant";
+  const char *ant = "ant";
+  const char *spider = "spider";
+  const char *millipede = "Illacme plenipes";
+  const char *eric = "half a bee";
+
+  /* A fresh hash_map should be empty.  */
+  EXPECT_EQ (0, m.elements ());
+  EXPECT_EQ (NULL, m.get (ostrich));
+
+  /* Populate the hash_map.  */
+  EXPECT_EQ (false, m.put (ostrich, 2));
+  EXPECT_EQ (false, m.put (elephant, 4));
+  EXPECT_EQ (false, m.put (ant, 6));
+  EXPECT_EQ (false, m.put (spider, 8));
+  EXPECT_EQ (false, m.put (millipede, 750));
+  EXPECT_EQ (false, m.put (eric, 3));
+
+  /* Verify that we can recover the stored values.  */
+  EXPECT_EQ (6, m.elements ());
+  EXPECT_EQ (2, *m.get (ostrich));
+  EXPECT_EQ (4, *m.get (elephant));
+  EXPECT_EQ (6, *m.get (ant));
+  EXPECT_EQ (8, *m.get (spider));
+  EXPECT_EQ (750, *m.get (millipede));
+  EXPECT_EQ (3, *m.get (eric));
+
+  /* Verify removing an item.  */
+  m.remove (eric);
+  EXPECT_EQ (5, m.elements ());
+  EXPECT_EQ (NULL, m.get (eric));
+}
+
+}  /* anon namespace.  */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 07/16] Add test-functions.c to unittests
  2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
                               ` (6 preceding siblings ...)
  2015-10-27 19:32             ` [PATCH 10/16] Add test-hash-map.c " David Malcolm
@ 2015-10-27 19:32             ` David Malcolm
  2015-10-30  5:19               ` Jeff Law
  2015-10-27 19:35             ` [PATCH 06/16] Add test-folding.c " David Malcolm
                               ` (10 subsequent siblings)
  18 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-10-27 19:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/testsuite/ChangeLog:
	* unittests/test-functions.c: New file.
---
 gcc/testsuite/unittests/test-functions.c | 645 +++++++++++++++++++++++++++++++
 1 file changed, 645 insertions(+)
 create mode 100644 gcc/testsuite/unittests/test-functions.c

diff --git a/gcc/testsuite/unittests/test-functions.c b/gcc/testsuite/unittests/test-functions.c
new file mode 100644
index 0000000..56630b5
--- /dev/null
+++ b/gcc/testsuite/unittests/test-functions.c
@@ -0,0 +1,645 @@
+/* Unit tests for function-handling.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "gtest/gtest.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "hard-reg-set.h"
+#include "input.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "gimple-expr.h"
+#include "toplev.h"
+#include "print-tree.h"
+#include "tree-iterator.h"
+#include "gimplify.h"
+#include "tree-cfg.h"
+#include "basic-block.h"
+#include "double-int.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "stmt.h"
+#include "hash-table.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "context.h"
+#include "hash-map.h"
+#include "plugin-api.h"
+#include "ipa-ref.h"
+#include "cgraph.h"
+
+namespace {
+
+class function_test : public ::testing::Test
+{
+ protected:
+  tree
+  make_fndecl (tree return_type,
+	       const char *name,
+	       vec <tree> &param_types,
+	       bool is_variadic = false)
+  {
+    tree fn_type;
+    if (is_variadic)
+      fn_type = build_varargs_function_type_array (return_type,
+						   param_types.length (),
+						   param_types.address ());
+    else
+      fn_type = build_function_type_array (return_type,
+					   param_types.length (),
+					   param_types.address ());
+    /* FIXME: this uses input_location: */
+    tree fndecl = build_fn_decl (name, fn_type);
+
+    return fndecl;
+  }
+};
+
+TEST_F (function_test, fndecl_int_void)
+{
+  auto_vec <tree> param_types;
+  tree fndecl = make_fndecl (integer_type_node,
+			     "test_fndecl_int_void",
+			     param_types);
+  ASSERT_TRUE (fndecl != NULL);
+  if (0)
+    debug_tree (fndecl);
+
+  /* Verify name of decl.  */
+  tree declname = DECL_NAME (fndecl);
+  ASSERT_TRUE (declname != NULL);
+  EXPECT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
+  /* We expect it to use a *copy* of the string we passed in.  */
+  const char *identifier_ptr = IDENTIFIER_POINTER (declname);
+  EXPECT_NE ("test_fndecl_int_void", identifier_ptr);
+  EXPECT_EQ (0, strcmp ("test_fndecl_int_void", identifier_ptr));
+
+  /* Verify type of fndecl.  */
+  EXPECT_EQ (FUNCTION_DECL, TREE_CODE (fndecl));
+  tree fntype = TREE_TYPE (fndecl);
+  EXPECT_EQ (FUNCTION_TYPE, TREE_CODE (fntype));
+
+  /* Verify return type.  */
+  EXPECT_EQ (integer_type_node, TREE_TYPE (fntype));
+
+  /* Verify "void" args.  */
+  tree argtypes = TYPE_ARG_TYPES (fntype);
+  EXPECT_EQ (TREE_LIST, TREE_CODE (argtypes));
+  EXPECT_EQ (void_type_node, TREE_VALUE (argtypes));
+  EXPECT_EQ (NULL, TREE_CHAIN (argtypes));
+}
+
+TEST_F (function_test, fndecl_float_intchar)
+{
+  auto_vec <tree> param_types;
+  param_types.safe_push (integer_type_node);
+  param_types.safe_push (char_type_node);
+  tree fndecl = make_fndecl (float_type_node,
+			     "test_fndecl_float_intchar",
+			     param_types);
+  ASSERT_TRUE (fndecl != NULL);
+  if (0)
+    debug_tree (fndecl);
+
+  /* Verify name of decl.  */
+  tree declname = DECL_NAME (fndecl);
+  ASSERT_TRUE (declname != NULL);
+  EXPECT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
+  /* We expect it to use a *copy* of the string we passed in.  */
+  const char *identifier_ptr = IDENTIFIER_POINTER (declname);
+  EXPECT_NE ("test_fndecl_float_intchar", identifier_ptr);
+  EXPECT_EQ (0, strcmp ("test_fndecl_float_intchar", identifier_ptr));
+
+  /* Verify type of fndecl.  */
+  EXPECT_EQ (FUNCTION_DECL, TREE_CODE (fndecl));
+  tree fntype = TREE_TYPE (fndecl);
+  EXPECT_EQ (FUNCTION_TYPE, TREE_CODE (fntype));
+
+  /* Verify return type.  */
+  EXPECT_EQ (float_type_node, TREE_TYPE (fntype));
+
+  /* Verify "(int, char)" args.  */
+  tree arg0 = TYPE_ARG_TYPES (fntype);
+  EXPECT_EQ (TREE_LIST, TREE_CODE (arg0));
+  EXPECT_EQ (integer_type_node, TREE_VALUE (arg0));
+  tree arg1 = TREE_CHAIN (arg0);
+  ASSERT_TRUE (arg1 != NULL);
+  EXPECT_EQ (TREE_LIST, TREE_CODE (arg1));
+  EXPECT_EQ (char_type_node, TREE_VALUE (arg1));
+  tree argterm = TREE_CHAIN (arg1);
+  ASSERT_TRUE (argterm != NULL);
+  EXPECT_EQ (TREE_LIST, TREE_CODE (argterm));
+  EXPECT_EQ (void_type_node, TREE_VALUE (argterm));
+  EXPECT_EQ (NULL, TREE_CHAIN (argterm));
+}
+
+/* The test cases using this fixture take a trivial function:
+
+     int test_fn (void) { return 42; }
+
+   and test various conversions done to it:
+
+   - gimplification
+   - construction of the CFG
+   - conversion to SSA form
+   - expansion to RTL form
+
+   In avoid having one overlong test case, this is broken
+   up into separate test cases for each stage, with helper methods
+   in this fixture to minimize code duplication.
+
+   Another approach would be to attempt to directly construct a function
+   in the appropriate representation at each stage, though presumably
+   that would exhibit different kinds of failure compared to this
+   approach.  */
+
+class representation_test : public function_test
+{
+ protected:
+  /* Construct this function:
+       int test_fn (void) { return 42; }
+     in generic tree form.  Return the fndecl.  */
+  tree
+  build_trivial_generic_function ()
+  {
+    auto_vec <tree> param_types;
+    tree fndecl = make_fndecl (integer_type_node,
+			       "test_fn",
+			       param_types);
+    EXPECT_TRUE (fndecl != NULL);
+
+    /* Populate the function.  */
+    tree retval = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+			      NULL_TREE, integer_type_node);
+    DECL_ARTIFICIAL (retval) = 1;
+    DECL_IGNORED_P (retval) = 1;
+    DECL_RESULT (fndecl) = retval;
+
+    /* Create a BIND_EXPR, and within it, a statement list.  */
+    tree stmt_list = alloc_stmt_list ();
+    tree_stmt_iterator stmt_iter = tsi_start (stmt_list);
+    tree block = make_node (BLOCK);
+    tree bind_expr =
+      build3 (BIND_EXPR, void_type_node, NULL, stmt_list, block);
+
+    tree modify_retval = build2 (MODIFY_EXPR,
+				 integer_type_node,
+				 retval,
+				 build_int_cst (integer_type_node, 42));
+    tree return_stmt = build1 (RETURN_EXPR,
+			       integer_type_node,
+			       modify_retval);
+    tsi_link_after (&stmt_iter, return_stmt, TSI_CONTINUE_LINKING);
+
+    DECL_INITIAL (fndecl) = block;
+
+    /* how to add to function? the following appears to be how to
+       set the body of a fndecl: */
+    DECL_SAVED_TREE(fndecl) = bind_expr;
+
+    /* Ensure that locals appear in the debuginfo.  */
+    BLOCK_VARS (block) = BIND_EXPR_VARS (bind_expr);
+
+    if (0)
+      debug_tree (fndecl);
+
+    return fndecl;
+  }
+
+  /* Construct this function:
+       int test_fn (void) { return 42; }
+     in "high gimple" form.  Return the fndecl.  */
+  tree
+  build_trivial_high_gimple_function ()
+  {
+    /* Construct a trivial function, and gimplify it: */
+    tree fndecl = build_trivial_generic_function ();
+    gimplify_function_tree (fndecl);
+    return fndecl;
+  }
+
+  /* Build a CFG for a function in gimple form.  */
+  void
+  build_cfg (tree fndecl)
+  {
+    function *fun = DECL_STRUCT_FUNCTION (fndecl);
+    ASSERT_TRUE (fun != NULL);
+    EXPECT_EQ (fndecl, fun->decl);
+
+    /* We first have to lower control flow; for our trivial test function
+       this gives us:
+	 test_fn ()
+	 {
+	   D.56 = 42;
+	   goto <D.57>;
+	   <D.57>:
+	   return D.56;
+	 }
+    */
+    gimple_opt_pass *lower_cf_pass = make_pass_lower_cf (g);
+    push_cfun (fun);
+    lower_cf_pass->execute (fun);
+    pop_cfun ();
+    if (0)
+      dump_function_to_file (fndecl, stderr, 0);
+
+    /* We can now convert to CFG form; for our trivial test function this
+       gives us:
+	 test_fn ()
+	 {
+	   <bb 2>:
+	   D.56 = 42;
+	   return D.56;
+	 }
+    */
+    gimple_opt_pass *build_cfg_pass = make_pass_build_cfg (g);
+    push_cfun (fun);
+    build_cfg_pass->execute (fun);
+    pop_cfun ();
+    if (0)
+      dump_function_to_file (fndecl, stderr, 0);
+  }
+
+  /* Convert a gimple+CFG function to SSA form.  */
+  void
+  convert_to_ssa (tree fndecl)
+  {
+    function *fun = DECL_STRUCT_FUNCTION (fndecl);
+    ASSERT_TRUE (fun != NULL);
+    EXPECT_EQ (fndecl, fun->decl);
+
+    gimple_opt_pass *pass_init_datastructures =
+      make_pass_init_datastructures (g);
+    gimple_opt_pass *build_ssa_pass = make_pass_build_ssa (g);
+    push_cfun (fun);
+    pass_init_datastructures->execute (fun);
+    build_ssa_pass->execute (fun);
+    pop_cfun ();
+  }
+
+  /* Assuming we have a simple 3-block CFG like this:
+       [ENTRY] -> [block2] -> [EXIT]
+     get the "real" basic block (block 2).  */
+  basic_block
+  get_real_block (function *fun)
+  {
+    EXPECT_TRUE (fun->cfg != NULL);
+    EXPECT_EQ (3, n_basic_blocks_for_fn (fun));
+    basic_block bb2 = (*fun->cfg->x_basic_block_info)[2];
+    EXPECT_TRUE (bb2 != NULL);
+    return bb2;
+  }
+
+  /* Verify that we have a simple 3-block CFG: the two "fake" ones, and
+     a "real" one:
+     [ENTRY] -> [block2] -> [EXIT].  */
+  void
+  verify_three_block_cfg (function *fun)
+  {
+    ASSERT_TRUE (fun->cfg != NULL);
+    EXPECT_EQ (3, n_basic_blocks_for_fn (fun));
+    EXPECT_EQ (2, n_edges_for_fn (fun));
+
+    /* The "fake" basic blocks.  */
+    basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (entry != NULL);
+    EXPECT_EQ (ENTRY_BLOCK, entry->index);
+
+    basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (exit != NULL);
+    EXPECT_EQ (EXIT_BLOCK, exit->index);
+
+    /* The "real" basic block.  */
+    basic_block bb2 = get_real_block (fun);
+    ASSERT_TRUE (bb2 != NULL);
+    EXPECT_EQ (2, bb2->index);
+
+    /* Verify connectivity.  */
+    EXPECT_EQ (NULL, entry->preds);
+    EXPECT_EQ (1, entry->succs->length ());
+
+    edge from_entry_to_bb2 = (*entry->succs)[0];
+    EXPECT_EQ (entry, from_entry_to_bb2->src);
+    EXPECT_EQ (bb2, from_entry_to_bb2->dest);
+
+    EXPECT_EQ (1, bb2->preds->length ());
+    EXPECT_EQ (from_entry_to_bb2, (*bb2->preds)[0]);
+    EXPECT_EQ (1, bb2->succs->length ());
+
+    edge from_bb2_to_exit = (*bb2->succs)[0];
+    EXPECT_EQ (bb2, from_bb2_to_exit->src);
+    EXPECT_EQ (exit, from_bb2_to_exit->dest);
+
+    EXPECT_EQ (1, exit->preds->length ());
+    EXPECT_EQ (from_bb2_to_exit, (*exit->preds)[0]);
+    EXPECT_EQ (NULL, exit->succs);
+  }
+
+  /* As above, but additionally verify the gimple statements are sane.  */
+  void
+  verify_three_block_gimple_cfg (function *fun)
+  {
+    verify_three_block_cfg (fun);
+
+    /* The "fake" basic blocks should be flagged as gimple, but with have no
+       statements.  */
+    basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (entry != NULL);
+    EXPECT_EQ (0, entry->flags & BB_RTL);
+    EXPECT_EQ (NULL, bb_seq (entry));
+
+    basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (exit != NULL);
+    EXPECT_EQ (0, entry->flags & BB_RTL);
+    EXPECT_EQ (NULL, bb_seq (exit));
+
+    /* The "real" basic block should be flagged as gimple, and have one
+       or more statements.  */
+    basic_block bb2 = get_real_block (fun);
+    ASSERT_TRUE (bb2 != NULL);
+    EXPECT_EQ (0, entry->flags & BB_RTL);
+    EXPECT_TRUE (bb_seq (bb2) != NULL);
+  }
+
+  /* As above, but additionally verify the RTL insns are sane.  */
+  void
+  verify_three_block_rtl_cfg (function *fun)
+  {
+    verify_three_block_cfg (fun);
+
+    /* The "fake" basic blocks should be flagged as RTL, but with no
+       insns.  */
+    basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (entry != NULL);
+    EXPECT_EQ (BB_RTL, entry->flags & BB_RTL);
+    EXPECT_EQ (NULL, BB_HEAD (entry));
+
+    basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (exit != NULL);
+    EXPECT_EQ (BB_RTL, entry->flags & BB_RTL);
+    EXPECT_EQ (NULL, BB_HEAD (exit));
+
+    /* The "real" basic block should be flagged as RTL, and have one
+       or more insns.  */
+    basic_block bb2 = get_real_block (fun);
+    ASSERT_TRUE (bb2 != NULL);
+    EXPECT_EQ (BB_RTL, entry->flags & BB_RTL);
+    EXPECT_TRUE (BB_HEAD (bb2) != NULL);
+  }
+
+};
+
+/* Test converting our trivial function:
+     int test_fn (void) { return 42; }
+   to gimple form.  */
+
+TEST_F (representation_test, gimplification)
+{
+  tree fndecl = build_trivial_generic_function ();
+
+  /* Convert to gimple: */
+  gimplify_function_tree (fndecl);
+
+  if (0)
+    dump_function_to_file (fndecl, stderr, 0);
+
+  /* Verify that we got gimple out of it.  */
+
+  /* The function is now in GIMPLE form but the CFG has not been
+     built yet.  */
+
+  /* We should have a struct function for the decl.  */
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  EXPECT_EQ (fndecl, fun->decl);
+
+  /* We expect a GIMPLE_BIND, with two gimple statements within it:
+       tmp = 42;
+       return tmp;  */
+
+  gimple_seq seq_fn_body = gimple_body (fndecl);
+  EXPECT_TRUE (seq_fn_body != NULL);
+  gimple *bind_stmt = gimple_seq_first_stmt (seq_fn_body);
+  EXPECT_EQ (GIMPLE_BIND, gimple_code (bind_stmt));
+  EXPECT_EQ (NULL, bind_stmt->next);
+
+  gimple_seq seq_bind_body = gimple_bind_body (as_a <gbind *> (bind_stmt));
+
+  /* Verify that we have the 2 statements we expect.  */
+  EXPECT_TRUE (seq_bind_body != NULL);
+  gimple *stmt1 = gimple_seq_first_stmt (seq_bind_body);
+  ASSERT_TRUE (stmt1 != NULL);
+  EXPECT_EQ (GIMPLE_ASSIGN, gimple_code (stmt1));
+  gimple *stmt2 = stmt1->next;
+  ASSERT_TRUE (stmt2 != NULL);
+  EXPECT_EQ (stmt1, stmt2->prev);
+  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt2));
+}
+
+/* Test of building a CFG for a function in high gimple form.  */
+
+TEST_F (representation_test, building_cfg)
+{
+  /* Construct a trivial function, and gimplify it: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+
+  /* Build a CFG.  */
+  build_cfg (fndecl);
+
+  /* The CFG-building code constructs a 4-block cfg (with
+     ENTRY and EXIT):
+       test_fn ()
+       {
+         <bb 2>:
+	 D.65 = 42;
+
+	 <bb 3>:
+	 return D.65;
+       }
+     and then ought to merge blocks 2 and 3 in cleanup_tree_cfg.
+
+     Hence we should end up with a simple 3-block cfg, the two "fake" ones,
+     and a "real" one:
+       [ENTRY] -> [block2] -> [EXIT]
+     with code like this:
+	 test_fn ()
+	 {
+	   <bb 2>:
+	   D.56 = 42;
+	   return D.56;
+	 }
+  */
+  verify_three_block_gimple_cfg (fun);
+
+  /* Verify the statements within the "real" block.  */
+  basic_block bb2 = get_real_block (fun);
+  gimple *stmt_a = gimple_seq_first_stmt (bb_seq (bb2));
+  EXPECT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a));
+  gimple *stmt_b = stmt_a->next;
+  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt_b));
+  EXPECT_EQ (NULL, stmt_b->next);
+}
+
+/* Test of conversion of gimple to SSA form.  */
+TEST_F (representation_test, conversion_to_ssa)
+{
+  /* As above, construct a trivial function, gimplify it, and build a CFG: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  build_cfg (fndecl);
+
+  convert_to_ssa (fndecl);
+
+  verify_three_block_gimple_cfg (fun);
+
+  /* For out trivial test function we should now have something like
+     this:
+       test_fn ()
+       {
+	 <bb 2>:
+	 _1 = 42;
+	 return _1;
+       }
+  */
+  if (0)
+    dump_function_to_file (fndecl, stderr, 0);
+  basic_block bb2 = get_real_block (fun);
+  gimple *stmt_a = gimple_seq_first_stmt (bb_seq (bb2));
+  EXPECT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a));
+
+  gimple *stmt_b = stmt_a->next;
+  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt_b));
+  EXPECT_EQ (NULL, stmt_b->next);
+
+  greturn *return_stmt = as_a <greturn *> (stmt_b);
+  EXPECT_EQ (SSA_NAME, TREE_CODE (gimple_return_retval (return_stmt)));
+}
+
+/* Test of expansion from gimple-ssa to RTL.  */
+
+TEST_F (representation_test, expansion_to_rtl)
+{
+  /* As above, construct a trivial function, gimplify it, build a CFG,
+     and convert to SSA: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  build_cfg (fndecl);
+  convert_to_ssa (fndecl);
+
+  /* We need a cgraph_node for it.  */
+  cgraph_node::get_create (fndecl);
+  /* Normally, cgraph_node::expand () would call
+     init_function_start (and a bunch of other stuff),
+     and invoke the expand pass, but it also runs
+     all of the other passes.  So just do the minimum
+     needed to get from gimple-SSA to RTL.  */
+  rtl_opt_pass *expand_pass = make_pass_expand (g);
+  push_cfun (fun);
+  init_function_start (fndecl);
+  expand_pass->execute (fun);
+  pop_cfun ();
+
+  /* On x86_64, I get this:
+       (note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+       (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
+       (insn 5 2 6 2 (set (reg:SI 87 [ D.59 ])
+			  (const_int 42 [0x2a])) -1 (nil))
+       (insn 6 5 10 2 (set (reg:SI 88 [ <retval> ])
+			   (reg:SI 87 [ D.59 ])) -1 (nil))
+       (insn 10 6 11 2 (set (reg/i:SI 0 ax)
+			    (reg:SI 88 [ <retval> ])) -1 (nil))
+       (insn 11 10 0 2 (use (reg/i:SI 0 ax)) -1 (nil))
+   */
+  if (0)
+    dump_function_to_file (fndecl, stderr, 0);
+
+  verify_three_block_rtl_cfg (fun);
+
+  /* Verify as much of the RTL as we can whilst avoiding
+     target-specific behavior.  */
+  basic_block bb2 = get_real_block (fun);
+
+  /* Expect a NOTE_INSN_BASIC_BLOCK... */
+  rtx_insn *insn = BB_HEAD (bb2);
+  ASSERT_TRUE (insn != NULL);
+  EXPECT_EQ (NOTE, insn->code);
+  EXPECT_EQ (NOTE_INSN_BASIC_BLOCK, NOTE_KIND (insn));
+  EXPECT_EQ (bb2, NOTE_BASIC_BLOCK (insn));
+
+  /* ...followed by a NOTE_INSN_FUNCTION_BEG...  */
+  insn = NEXT_INSN (insn);
+  ASSERT_TRUE (insn != NULL);
+  EXPECT_EQ (NOTE, insn->code);
+  EXPECT_EQ (NOTE_INSN_FUNCTION_BEG, NOTE_KIND (insn));
+
+  /* ...followed by a SET of a reg to the const value.  */
+  insn = NEXT_INSN (insn);
+  ASSERT_TRUE (insn != NULL);
+  EXPECT_EQ (INSN, insn->code);
+  rtx pat = PATTERN (insn);
+  ASSERT_TRUE (pat != NULL);
+  EXPECT_EQ (SET, pat->code);
+  EXPECT_EQ (REG, SET_DEST (pat)->code);
+  EXPECT_EQ (CONST_INT, SET_SRC (pat)->code);
+  EXPECT_EQ (42, INTVAL (SET_SRC (pat)));
+
+  /* ...etc; any further checks are likely to over-specify things
+     and run us into target dependencies.  */
+}
+
+}  // anon namespace
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 04/16] Add test-cfg.c to unittests
  2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
                               ` (4 preceding siblings ...)
  2015-10-27 19:31             ` [PATCH 01/16] Add unittest infrastructure David Malcolm
@ 2015-10-27 19:32             ` David Malcolm
  2015-10-29 22:23               ` Jeff Law
  2015-10-27 19:32             ` [PATCH 10/16] Add test-hash-map.c " David Malcolm
                               ` (12 subsequent siblings)
  18 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-10-27 19:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/testsuite/ChangeLog:
	* unittests/test-cfg.c: New file.
---
 gcc/testsuite/unittests/test-cfg.c | 319 +++++++++++++++++++++++++++++++++++++
 1 file changed, 319 insertions(+)
 create mode 100644 gcc/testsuite/unittests/test-cfg.c

diff --git a/gcc/testsuite/unittests/test-cfg.c b/gcc/testsuite/unittests/test-cfg.c
new file mode 100644
index 0000000..79d5d37
--- /dev/null
+++ b/gcc/testsuite/unittests/test-cfg.c
@@ -0,0 +1,319 @@
+/* Unit tests for CFG-handling.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "gtest/gtest.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "pretty-print.h"
+#include "tree-cfg.h"
+#include "predict.h"
+#include "basic-block.h"
+#include "hard-reg-set.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfghooks.h"
+
+namespace {
+
+class cfg_test : public ::testing::Test
+{
+ protected:
+  tree
+  push_fndecl (const char *name)
+  {
+    tree fn_type = build_function_type_array (integer_type_node, /* return_type */
+					    0, NULL);
+    /* FIXME: this uses input_location: */
+    tree fndecl = build_fn_decl (name, fn_type);
+    tree retval = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+			      NULL_TREE, integer_type_node);
+    DECL_RESULT (fndecl) = retval;
+    push_struct_function (fndecl);
+    function *fun = DECL_STRUCT_FUNCTION (fndecl);
+    EXPECT_TRUE (fun != NULL);
+    init_empty_tree_cfg_for_function (fun);
+    EXPECT_EQ (2, n_basic_blocks_for_fn (fun));
+    EXPECT_EQ (0, n_edges_for_fn (fun));
+    return fndecl;
+  }
+};
+
+/* These tests directly create CFGs.
+   Compare with the static fns within tree-cfg.c:
+     - build_gimple_cfg
+     - make_blocks: calls create_basic_block (seq, bb);
+     - make_edges.   */
+
+/* Verify a simple cfg of the form:
+     ENTRY -> A -> B -> C -> EXIT.  */
+TEST_F (cfg_test, linear_chain)
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_test_linear_chain");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  EXPECT_TRUE (fun != NULL);
+
+  EXPECT_EQ (2, n_basic_blocks_for_fn (fun));
+  EXPECT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create some empty blocks.  */
+  basic_block bb_a = create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun));
+  basic_block bb_b = create_empty_bb (bb_a);
+  basic_block bb_c = create_empty_bb (bb_b);
+
+  EXPECT_EQ (5, n_basic_blocks_for_fn (fun));
+  EXPECT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create some edges: a simple linear chain of BBs.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), bb_a, EDGE_FALLTHRU);
+  make_edge (bb_a, bb_b, 0);
+  make_edge (bb_b, bb_c, 0);
+  make_edge (bb_c, EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+
+  /* Verify the edges.  */
+  EXPECT_EQ (4, n_edges_for_fn (fun));
+  EXPECT_EQ (NULL, ENTRY_BLOCK_PTR_FOR_FN (fun)->preds);
+  EXPECT_EQ (1, ENTRY_BLOCK_PTR_FOR_FN (fun)->succs->length ());
+  EXPECT_EQ (1, bb_a->preds->length ());
+  EXPECT_EQ (1, bb_a->succs->length ());
+  EXPECT_EQ (1, bb_b->preds->length ());
+  EXPECT_EQ (1, bb_b->succs->length ());
+  EXPECT_EQ (1, bb_c->preds->length ());
+  EXPECT_EQ (1, bb_c->succs->length ());
+  EXPECT_EQ (1, EXIT_BLOCK_PTR_FOR_FN (fun)->preds->length ());
+  EXPECT_EQ (NULL, EXIT_BLOCK_PTR_FOR_FN (fun)->succs);
+
+  /* Verify the dominance information
+     Each BB in our simple chain should be dominated by the one before
+     it.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  EXPECT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
+  EXPECT_EQ (bb_b, get_immediate_dominator (CDI_DOMINATORS, bb_c));
+  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
+  EXPECT_EQ (1, dom_by_b.length ());
+  EXPECT_EQ (bb_c, dom_by_b[0]);
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance: each BB in our chain is post-dominated
+     by the one after it.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  EXPECT_EQ (bb_b, get_immediate_dominator (CDI_POST_DOMINATORS, bb_a));
+  EXPECT_EQ (bb_c, get_immediate_dominator (CDI_POST_DOMINATORS, bb_b));
+  vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
+  EXPECT_EQ (1, postdom_by_b.length ());
+  EXPECT_EQ (bb_a, postdom_by_b[0]);
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+/* Verify a simple CFG of the form:
+     ENTRY
+       |
+       A
+      / \
+     /t  \f
+    B     C
+     \   /
+      \ /
+       D
+       |
+      EXIT.  */
+TEST_F (cfg_test, diamond)
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_test_diamond");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  EXPECT_TRUE (fun != NULL);
+
+  EXPECT_EQ (2, n_basic_blocks_for_fn (fun));
+  EXPECT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create some empty blocks.  */
+  basic_block bb_a = create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun));
+  basic_block bb_b = create_empty_bb (bb_a);
+  basic_block bb_c = create_empty_bb (bb_a);
+  basic_block bb_d = create_empty_bb (bb_b);
+
+  EXPECT_EQ (6, n_basic_blocks_for_fn (fun));
+  EXPECT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create the edges.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), bb_a, EDGE_FALLTHRU);
+  make_edge (bb_a, bb_b, EDGE_TRUE_VALUE);
+  make_edge (bb_a, bb_c, EDGE_FALSE_VALUE);
+  make_edge (bb_b, bb_d, 0);
+  make_edge (bb_c, bb_d, 0);
+  make_edge (bb_d, EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+
+  /* Verify the edges.  */
+  EXPECT_EQ (6, n_edges_for_fn (fun));
+  EXPECT_EQ (1, bb_a->preds->length ());
+  EXPECT_EQ (2, bb_a->succs->length ());
+  EXPECT_EQ (1, bb_b->preds->length ());
+  EXPECT_EQ (1, bb_b->succs->length ());
+  EXPECT_EQ (1, bb_c->preds->length ());
+  EXPECT_EQ (1, bb_c->succs->length ());
+  EXPECT_EQ (2, bb_d->preds->length ());
+  EXPECT_EQ (1, bb_d->succs->length ());
+
+  /* Verify the dominance information.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  EXPECT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
+  EXPECT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_c));
+  EXPECT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_d));
+  vec<basic_block> dom_by_a = get_dominated_by (CDI_DOMINATORS, bb_a);
+  EXPECT_EQ (3, dom_by_a.length ()); /* B, C, D, in some order.  */
+  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
+  EXPECT_EQ (0, dom_by_b.length ());
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  EXPECT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_a));
+  EXPECT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_b));
+  EXPECT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_c));
+  vec<basic_block> postdom_by_d = get_dominated_by (CDI_POST_DOMINATORS, bb_d);
+  EXPECT_EQ (3, postdom_by_d.length ()); /* A, B, C in some order.  */
+  vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
+  EXPECT_EQ (0, postdom_by_b.length ());
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+/* Verify that we can handle a CFG containing a "complete" aka
+   fully-connected subgraph (where A B C D below all have edges
+   pointing to each other node, also to themselves).
+   e.g.:
+     ENTRY  EXIT
+       |    ^
+       |   /
+       |  /
+       | /
+       V/
+       A<--->B
+       ^^   ^^
+       | \ / |
+       |  X  |
+       | / \ |
+       VV   VV
+       C<--->D
+*/
+TEST_F (cfg_test, fully_connected)
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_fully_connected");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  EXPECT_TRUE (fun != NULL);
+
+  EXPECT_EQ (2, n_basic_blocks_for_fn (fun));
+  EXPECT_EQ (0, n_edges_for_fn (fun));
+
+  const int n = 4;
+
+  /* Create some empty blocks.  */
+  auto_vec <basic_block> subgraph_nodes;
+  for (int i = 0; i < n; i++)
+    subgraph_nodes.safe_push (create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun)));
+
+  EXPECT_EQ (n + 2, n_basic_blocks_for_fn (fun));
+  EXPECT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create the edges.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), subgraph_nodes[0], EDGE_FALLTHRU);
+  make_edge (subgraph_nodes[0], EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+  for (int i = 0; i < n; i++)
+    for (int j = 0; j < n; j++)
+      make_edge (subgraph_nodes[i], subgraph_nodes[j], 0);
+
+  /* Verify the edges.  */
+  EXPECT_EQ (2 + (n * n), n_edges_for_fn (fun));
+  /* The first one is linked to ENTRY/EXIT as well as itself and
+     everything else.  */
+  EXPECT_EQ (n + 1, subgraph_nodes[0]->preds->length ());
+  EXPECT_EQ (n + 1, subgraph_nodes[0]->succs->length ());
+  /* The other ones in the subgraph are linked to everything in
+     the subgraph (including themselves).  */
+  for (int i = 1; i < n; i++)
+    {
+      EXPECT_EQ (n, subgraph_nodes[i]->preds->length ());
+      EXPECT_EQ (n, subgraph_nodes[i]->succs->length ());
+    }
+
+  /* Verify the dominance information.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  /* The initial block in the subgraph should be dominated by ENTRY.  */
+  EXPECT_EQ (ENTRY_BLOCK_PTR_FOR_FN (fun),
+	     get_immediate_dominator (CDI_DOMINATORS,
+				      subgraph_nodes[0]));
+  /* Every other block in the subgraph should be dominated by the
+     initial block.  */
+  for (int i = 1; i < n; i++)
+    EXPECT_EQ (subgraph_nodes[0],
+	       get_immediate_dominator (CDI_DOMINATORS,
+					subgraph_nodes[i]));
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  /* The initial block in the subgraph should be postdominated by EXIT.  */
+  EXPECT_EQ (EXIT_BLOCK_PTR_FOR_FN (fun),
+	     get_immediate_dominator (CDI_POST_DOMINATORS,
+				      subgraph_nodes[0]));
+  /* Every other block in the subgraph should be postdominated by the
+     initial block, since that leads to EXIT.  */
+  for (int i = 1; i < n; i++)
+    EXPECT_EQ (subgraph_nodes[0],
+	       get_immediate_dominator (CDI_POST_DOMINATORS,
+					subgraph_nodes[i]));
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+}  /* anon namespace.  */
+
+/* TODO: test the dominator/postdominator logic with various graphs/nodes:
+   - loop
+   - nested loops
+   - switch statement (a block with many out-edges)
+   - something that jumps to itself
+   - etc  */
+
+/* TODO: add tests for loop-detection here?  */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 06/16] Add test-folding.c to unittests
  2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
                               ` (7 preceding siblings ...)
  2015-10-27 19:32             ` [PATCH 07/16] Add test-functions.c " David Malcolm
@ 2015-10-27 19:35             ` David Malcolm
  2015-10-30  5:06               ` Jeff Law
  2015-10-27 19:48             ` [PATCH 14/16] Add test-tree.c " David Malcolm
                               ` (9 subsequent siblings)
  18 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-10-27 19:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/testsuite/ChangeLog:
	* unittests/test-folding.c: New file.
---
 gcc/testsuite/unittests/test-folding.c | 120 +++++++++++++++++++++++++++++++++
 1 file changed, 120 insertions(+)
 create mode 100644 gcc/testsuite/unittests/test-folding.c

diff --git a/gcc/testsuite/unittests/test-folding.c b/gcc/testsuite/unittests/test-folding.c
new file mode 100644
index 0000000..6623c55
--- /dev/null
+++ b/gcc/testsuite/unittests/test-folding.c
@@ -0,0 +1,120 @@
+/* Unit tests for GCC's expression folding.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "gtest/gtest.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "hard-reg-set.h"
+#include "input.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "gimple-expr.h"
+#include "toplev.h"
+#include "print-tree.h"
+#include "tree-iterator.h"
+#include "gimplify.h"
+#include "tree-cfg.h"
+#include "fold-const.h"
+
+namespace {
+
+/* A test fixture for writing tests of folding trees.  */
+class tree_folding_test : public ::testing::Test
+{
+ protected:
+  void
+  assert_binop_folds_to_const (tree lhs, enum tree_code code, tree rhs,
+			       tree constant)
+  {
+    EXPECT_EQ (constant, fold_build2 (code, TREE_TYPE (lhs), lhs, rhs));
+  }
+
+  void
+  assert_binop_folds_to_nonlvalue (tree lhs, enum tree_code code, tree rhs,
+				   tree wrapped_expr)
+  {
+    tree result = fold_build2 (code, TREE_TYPE (lhs), lhs, rhs);
+    EXPECT_NE (wrapped_expr, result);
+    EXPECT_EQ (NON_LVALUE_EXPR, TREE_CODE (result));
+    EXPECT_EQ (wrapped_expr, TREE_OPERAND (result, 0));
+  }
+};
+
+TEST_F (tree_folding_test, arithmetic_folding)
+{
+  tree type = integer_type_node;
+  tree x = create_tmp_var_raw (type, "x");
+  tree zero = build_zero_cst (type);
+  tree one = build_int_cst (type, 1);
+
+  /* Addition.  */
+  /* 1 <-- (0 + 1) */
+  assert_binop_folds_to_const (zero, PLUS_EXPR, one,
+			       one);
+  assert_binop_folds_to_const (one, PLUS_EXPR, zero,
+			       one);
+
+  /* (nonlvalue)x <-- (x + 0) */
+  assert_binop_folds_to_nonlvalue (x, PLUS_EXPR, zero,
+				   x);
+
+  /* Subtraction.  */
+  /* 0 <-- (x - x) */
+  assert_binop_folds_to_const (x, MINUS_EXPR, x,
+			       zero);
+  assert_binop_folds_to_nonlvalue (x, MINUS_EXPR, zero,
+				   x);
+
+  /* Multiplication.  */
+  /* 0 <-- (x * 0) */
+  assert_binop_folds_to_const (x, MULT_EXPR, zero,
+			       zero);
+
+  /* (nonlvalue)x <-- (x * 1) */
+  assert_binop_folds_to_nonlvalue (x, MULT_EXPR, one,
+				   x);
+}
+
+}  // anon namespace
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 14/16] Add test-tree.c to unittests
  2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
                               ` (8 preceding siblings ...)
  2015-10-27 19:35             ` [PATCH 06/16] Add test-folding.c " David Malcolm
@ 2015-10-27 19:48             ` David Malcolm
  2015-10-30  5:00               ` Jeff Law
  2015-10-27 19:49             ` [PATCH 08/16] Add test-ggc.c " David Malcolm
                               ` (8 subsequent siblings)
  18 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-10-27 19:48 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/testsuite/ChangeLog:
	* unittests/test-tree.c: New file.
---
 gcc/testsuite/unittests/test-tree.c | 101 ++++++++++++++++++++++++++++++++++++
 1 file changed, 101 insertions(+)
 create mode 100644 gcc/testsuite/unittests/test-tree.c

diff --git a/gcc/testsuite/unittests/test-tree.c b/gcc/testsuite/unittests/test-tree.c
new file mode 100644
index 0000000..39754af
--- /dev/null
+++ b/gcc/testsuite/unittests/test-tree.c
@@ -0,0 +1,101 @@
+/* Unit tests for GCC's tree types.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "gtest/gtest.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "hard-reg-set.h"
+#include "input.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "gimple-expr.h"
+#include "toplev.h"
+#include "print-tree.h"
+#include "tree-iterator.h"
+#include "gimplify.h"
+#include "tree-cfg.h"
+#include "fold-const.h"
+
+namespace {
+
+/* Verify that integer constants are sane.  */
+
+TEST (tree_test, integer_constants)
+{
+  ASSERT_TRUE (integer_type_node != NULL);
+  EXPECT_TRUE (build_int_cst (integer_type_node, 0) != NULL);
+
+  tree type = integer_type_node;
+
+  tree zero = build_zero_cst (type);
+  EXPECT_EQ (INTEGER_CST, TREE_CODE (zero));
+  EXPECT_EQ (type, TREE_TYPE (zero));
+
+  tree one = build_int_cst (type, 1);
+  EXPECT_EQ (INTEGER_CST, TREE_CODE (one));
+  EXPECT_EQ (type, TREE_TYPE (zero));
+}
+
+/* Verify identifiers.  */
+
+TEST (tree_test, identifiers)
+{
+  tree identifier = get_identifier ("foo");
+  EXPECT_EQ (3, IDENTIFIER_LENGTH (identifier));
+  EXPECT_STREQ ("foo", IDENTIFIER_POINTER (identifier));
+}
+
+/* Verify LABEL_DECL.  */
+
+TEST (tree_test, labels)
+{
+  tree identifier = get_identifier ("err");
+  tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
+				identifier, void_type_node);
+  EXPECT_EQ (-1, LABEL_DECL_UID (label_decl));
+  EXPECT_FALSE (FORCED_LABEL (label_decl));
+}
+
+}  // anon namespace
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 08/16] Add test-ggc.c to unittests
  2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
                               ` (9 preceding siblings ...)
  2015-10-27 19:48             ` [PATCH 14/16] Add test-tree.c " David Malcolm
@ 2015-10-27 19:49             ` David Malcolm
  2015-10-30  5:08               ` Jeff Law
  2015-10-27 19:49             ` [PATCH 12/16] Add test-locations.c " David Malcolm
                               ` (7 subsequent siblings)
  18 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-10-27 19:49 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/testsuite/ChangeLog:
	* unittests/test-ggc.c: New file.
---
 gcc/testsuite/unittests/test-ggc.c | 299 +++++++++++++++++++++++++++++++++++++
 1 file changed, 299 insertions(+)
 create mode 100644 gcc/testsuite/unittests/test-ggc.c

diff --git a/gcc/testsuite/unittests/test-ggc.c b/gcc/testsuite/unittests/test-ggc.c
new file mode 100644
index 0000000..7a16977
--- /dev/null
+++ b/gcc/testsuite/unittests/test-ggc.c
@@ -0,0 +1,299 @@
+/* Unit tests for GCC's garbage collector (and gengtype etc).
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "gtest/gtest.h"
+#include "system.h"
+#include "coretypes.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "ggc-internal.h" /* (for ggc_force_collect).  */
+
+/* The various GTY markers must be outside of a namespace to be seen by
+   gengtype, so we don't put this file within an anonymous namespace.  */
+
+/* A test fixture for writing ggc tests.  */
+class ggc_test : public ::testing::Test
+{
+ protected:
+  void
+  forcibly_ggc_collect ()
+  {
+    ggc_force_collect = true;
+    ggc_collect ();
+    ggc_force_collect = false;
+  }
+};
+
+/* Smoketest to ensure that a GC root is marked ("tree" type).  */
+
+static GTY(()) tree dummy_unittesting_tree;
+
+TEST_F (ggc_test, tree_marking)
+{
+  dummy_unittesting_tree = build_int_cst (integer_type_node, 1066);
+
+  forcibly_ggc_collect ();
+
+  EXPECT_TRUE (ggc_marked_p (dummy_unittesting_tree));
+}
+
+/* Verify that a simple custom struct works, and that it can
+   own references to non-roots, and have them be marked.  */
+
+struct GTY(()) test_struct
+{
+  test_struct *other;
+};
+
+static GTY(()) test_struct *root_test_struct;
+
+TEST_F (ggc_test, custom_struct)
+{
+  root_test_struct = ggc_cleared_alloc <test_struct> ();
+  root_test_struct->other = ggc_cleared_alloc <test_struct> ();
+
+  forcibly_ggc_collect ();
+
+  EXPECT_TRUE (ggc_marked_p (root_test_struct));
+  EXPECT_TRUE (ggc_marked_p (root_test_struct->other));
+}
+
+/* Verify that destructors get run when instances are collected.  */
+
+struct GTY(()) test_struct_with_dtor
+{
+  /* This struct has a destructor; it *ought* to be called
+     by the ggc machinery when instances are collected.  */
+  ~test_struct_with_dtor () { dtor_call_count++; }
+
+  static int dtor_call_count;
+};
+
+int test_struct_with_dtor::dtor_call_count;
+
+TEST_F (ggc_test, finalization)
+{
+  EXPECT_FALSE (need_finalization_p <test_struct> ());
+  EXPECT_TRUE (need_finalization_p <test_struct_with_dtor> ());
+
+  /* Create some garbage.  */
+  const int count = 10;
+  for (int i = 0; i < count; i++)
+    ggc_cleared_alloc <test_struct_with_dtor> ();
+
+  test_struct_with_dtor::dtor_call_count = 0;
+
+  forcibly_ggc_collect ();
+
+  /* Verify that the destructor was run for each instance.  */
+  EXPECT_EQ (count, test_struct_with_dtor::dtor_call_count);
+}
+
+/* Verify that a global can be marked as "deletable".  */
+
+static GTY((deletable)) test_struct *test_of_deletable;
+
+/* FIXME: we can't do this test via a plugin as it stands.
+   The list of deletable roots is fixed by the main gengtype
+   run; there isn't yet a way to add extra
+   deletable roots (PLUGIN_REGISTER_GGC_ROOTS is for regular
+   roots).  */
+#if 0
+TEST_F (ggc_test, deletable_global)
+{
+  test_of_deletable = ggc_cleared_alloc <test_struct> ();
+  EXPECT_TRUE (test_of_deletable != NULL);
+
+  forcibly_ggc_collect ();
+
+  EXPECT_EQ (NULL, test_of_deletable);
+}
+#endif
+
+/* Verify that gengtype etc can cope with inheritance.  */
+
+class GTY((desc("%h.m_kind"), tag("0"))) example_base
+{
+ public:
+  example_base ()
+    : m_kind (0),
+      m_a (ggc_cleared_alloc <test_struct> ())
+  {}
+
+  void *
+  operator new (size_t sz)
+  {
+    return ggc_internal_cleared_alloc (sz);
+  }
+
+ protected:
+  example_base (int kind)
+    : m_kind (kind),
+      m_a (ggc_cleared_alloc <test_struct> ())
+  {}
+
+ public:
+  int m_kind;
+  test_struct *m_a;
+};
+
+class GTY((tag("1"))) some_subclass : public example_base
+{
+ public:
+  some_subclass ()
+    : example_base (1),
+      m_b (ggc_cleared_alloc <test_struct> ())
+  {}
+
+  test_struct *m_b;
+};
+
+class GTY((tag("2"))) some_other_subclass : public example_base
+{
+ public:
+  some_other_subclass ()
+    : example_base (2),
+      m_c (ggc_cleared_alloc <test_struct> ())
+  {}
+
+  test_struct *m_c;
+};
+
+/* Various test roots, both expressed as a ptr to the actual class, and
+   as a ptr to the base class.  */
+static GTY(()) example_base *test_example_base;
+static GTY(()) some_subclass *test_some_subclass;
+static GTY(()) some_other_subclass *test_some_other_subclass;
+static GTY(()) example_base *test_some_subclass_as_base_ptr;
+static GTY(()) example_base *test_some_other_subclass_as_base_ptr;
+
+TEST_F (ggc_test, inheritance)
+{
+  test_example_base = new example_base ();
+  test_some_subclass = new some_subclass ();
+  test_some_other_subclass = new some_other_subclass ();
+  test_some_subclass_as_base_ptr = new some_subclass ();
+  test_some_other_subclass_as_base_ptr = new some_other_subclass ();
+
+  forcibly_ggc_collect ();
+
+  /* Verify that the roots and everything referenced by them got marked
+     (both for fields in the base class and those in subclasses).  */
+  EXPECT_TRUE (ggc_marked_p (test_example_base));
+  EXPECT_TRUE (ggc_marked_p (test_example_base->m_a));
+
+  EXPECT_TRUE (ggc_marked_p (test_some_subclass));
+  EXPECT_TRUE (ggc_marked_p (test_some_subclass->m_a));
+  EXPECT_TRUE (ggc_marked_p (test_some_subclass->m_b));
+
+  EXPECT_TRUE (ggc_marked_p (test_some_other_subclass));
+  EXPECT_TRUE (ggc_marked_p (test_some_other_subclass->m_a));
+  EXPECT_TRUE (ggc_marked_p (test_some_other_subclass->m_c));
+
+  EXPECT_TRUE (ggc_marked_p (test_some_subclass_as_base_ptr));
+  EXPECT_TRUE (ggc_marked_p (test_some_subclass_as_base_ptr->m_a));
+  EXPECT_TRUE (ggc_marked_p (((some_subclass *)
+			      test_some_subclass_as_base_ptr)->m_b));
+
+  EXPECT_TRUE (ggc_marked_p (test_some_other_subclass_as_base_ptr));
+  EXPECT_TRUE (ggc_marked_p (test_some_other_subclass_as_base_ptr->m_a));
+  EXPECT_TRUE (ggc_marked_p (((some_other_subclass *)
+			      test_some_other_subclass_as_base_ptr)->m_c));
+}
+
+/* Test of chain_next/chain_prev
+
+   Construct a very long linked list, so that without
+   the chain_next/chain_prev optimization we'd have
+   a stack overflow when gt_ggc_mx_test_node recurses.  */
+
+struct GTY(( chain_next ("%h.m_next"),
+	     chain_prev ("%h.m_prev") )) test_node
+{
+  test_node *m_prev;
+  test_node *m_next;
+  int m_idx;
+};
+
+static GTY(()) test_node *root_test_node;
+
+TEST_F (ggc_test, chain_next)
+{
+  /* 2 million nodes (and thus the same number of stack frames) ought
+     to be deep enough to crash if gengtype has created something
+     that recurses.
+
+     This length reliably causes the test to segfault without the
+     chain_next/prev optimization on this box (Fedora 20 x86_64 with 128GB
+     of RAM), but causes this test to take about 0.5s, dominating the time
+     taken by the overall testsuite.
+
+     We could perhaps lower this by not increasing the stack size so much
+     in toplev.c, or perhaps reducing the stack size when running this
+     testcase.  */
+  const int count = 2000000;
+
+  /* Build the linked list.  */
+  root_test_node = ggc_cleared_alloc <test_node> ();
+  test_node *tail_node = root_test_node;
+  for (int i = 0; i < count; i++)
+    {
+      test_node *new_node = ggc_cleared_alloc <test_node> ();
+      tail_node->m_next = new_node;
+      new_node->m_prev = tail_node;
+      new_node->m_idx = i;
+      tail_node = new_node;
+    }
+
+  forcibly_ggc_collect ();
+
+  /* If we got here, we survived.  */
+
+  /* Verify that all nodes in the list were marked.  */
+  EXPECT_TRUE (ggc_marked_p (root_test_node));
+  test_node *iter_node = root_test_node->m_next;
+  for (int i = 0; i < count; i++)
+    {
+      EXPECT_TRUE (ggc_marked_p (iter_node));
+      EXPECT_EQ (i, iter_node->m_idx);
+      iter_node = iter_node->m_next;
+    }
+}
+
+/* Ideas for other tests:
+   - pch-handling  */
+
+/* Generated by unittests-plugin.c's use of the
+   "dg-plugin-run-gengtype" directive.  */
+#include "gt-unittests-test-ggc.h"
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 12/16] Add test-locations.c to unittests
  2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
                               ` (10 preceding siblings ...)
  2015-10-27 19:49             ` [PATCH 08/16] Add test-ggc.c " David Malcolm
@ 2015-10-27 19:49             ` David Malcolm
  2015-10-30  5:09               ` Jeff Law
  2015-10-27 19:50             ` [PATCH 13/16] Add test-rtl.c " David Malcolm
                               ` (6 subsequent siblings)
  18 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-10-27 19:49 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/testsuite/ChangeLog:
	* unittests/test-locations.c: New file.
---
 gcc/testsuite/unittests/test-locations.c | 145 +++++++++++++++++++++++++++++++
 1 file changed, 145 insertions(+)
 create mode 100644 gcc/testsuite/unittests/test-locations.c

diff --git a/gcc/testsuite/unittests/test-locations.c b/gcc/testsuite/unittests/test-locations.c
new file mode 100644
index 0000000..ef7eaee
--- /dev/null
+++ b/gcc/testsuite/unittests/test-locations.c
@@ -0,0 +1,145 @@
+/* Unit tests for GCC's source location-handling (and thus libcpp).
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "gtest/gtest.h"
+#include "system.h"
+#include "coretypes.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+
+namespace {
+
+/* Fixture for testing location-handling.
+   Creates some pre-canned location_t values.  */
+
+class location_test : public ::testing::Test
+{
+ protected:
+  location_test ()
+  {
+    /* Build a simple linemap describing some locations. */
+    linemap_add (line_table, LC_ENTER, false, "foo.c", 0);
+
+    linemap_line_start (line_table, 1, 100);
+    loc_a = linemap_position_for_column (line_table, 1);
+    loc_b = linemap_position_for_column (line_table, 23);
+
+    linemap_line_start (line_table, 2, 100);
+    loc_c = linemap_position_for_column (line_table, 1);
+    loc_d = linemap_position_for_column (line_table, 17);
+
+    /* Example of a very long line.  */
+    linemap_line_start (line_table, 3, 2000);
+    loc_e = linemap_position_for_column (line_table, 700);
+
+    linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+
+    /* Multiple files.  */
+    linemap_add (line_table, LC_ENTER, false, "bar.c", 0);
+    linemap_line_start (line_table, 1, 200);
+    loc_f = linemap_position_for_column (line_table, 150);
+    linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+  }
+
+  /* Verify the result of LOCATION_FILE/LOCATION_LINE/LOCATION_COLUMN
+     on LOC.  */
+  void
+  expect_loceq (const char *exp_filename,
+		int exp_linenum,
+		int exp_colnum,
+		location_t loc)
+  {
+    EXPECT_STREQ (exp_filename, LOCATION_FILE (loc));
+    EXPECT_EQ (exp_linenum, LOCATION_LINE (loc));
+    EXPECT_EQ (exp_colnum, LOCATION_COLUMN (loc));
+  }
+
+  location_t loc_a;
+  location_t loc_b;
+  location_t loc_c;
+  location_t loc_d;
+  location_t loc_e;
+  location_t loc_f;
+};
+
+/* Verify basic operation of ordinary linemaps.  */
+
+TEST_F (location_test, accessing_ordinary_linemaps)
+{
+  /* Verify that we can recover the location info.  */
+  expect_loceq ("foo.c", 1, 1, loc_a);
+  expect_loceq ("foo.c", 1, 23, loc_b);
+  expect_loceq ("foo.c", 2, 1, loc_c);
+  expect_loceq ("foo.c", 2, 17, loc_d);
+  expect_loceq ("foo.c", 3, 700, loc_e);
+  expect_loceq ("bar.c", 1, 150, loc_f);
+}
+
+TEST_F (location_test, unknown_location)
+{
+  EXPECT_EQ (NULL, LOCATION_FILE (UNKNOWN_LOCATION));
+  EXPECT_EQ (0, LOCATION_LINE (UNKNOWN_LOCATION));
+  EXPECT_EQ (0, LOCATION_COLUMN (UNKNOWN_LOCATION));
+}
+
+TEST_F (location_test, builtins)
+{
+  expect_loceq ("<built-in>", 0, 0, BUILTINS_LOCATION);
+  EXPECT_PRED1 (is_location_from_builtin_token, BUILTINS_LOCATION);
+  EXPECT_FALSE (is_location_from_builtin_token (loc_a));
+}
+
+/* Verify reading of input files (e.g. for caret-based diagnostics.  */
+
+TEST_F (location_test, reading_source_line)
+{
+  /* We will read *this* source file, using __FILE__.
+     Here is some specific text to read and test for:
+     The quick brown fox jumps over the lazy dog.  */
+  const int linenum_after_test_message = __LINE__;
+  const int linenum = linenum_after_test_message - 1;
+
+  int line_size;
+  const char *source_line = location_get_source_line (__FILE__, linenum, &line_size);
+  //FIXME: fix the path:  __FILE__ is that seen when compiling the plugin
+  //Make it absolute
+#if 0
+  EXPECT_TRUE (source_line != NULL);
+  EXPECT_STREQ ("     The quick brown fox jumps over the lazy dog.  */",
+		source_line);
+  EXPECT_EQ (53, line_size);
+#endif
+}
+
+} /* anon namespace. */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 13/16] Add test-rtl.c to unittests
  2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
                               ` (11 preceding siblings ...)
  2015-10-27 19:49             ` [PATCH 12/16] Add test-locations.c " David Malcolm
@ 2015-10-27 19:50             ` David Malcolm
  2015-10-30  4:58               ` Jeff Law
  2015-10-27 19:51             ` [PATCH 16/16] Add test-wide-int.c " David Malcolm
                               ` (5 subsequent siblings)
  18 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-10-27 19:50 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/testsuite/ChangeLog:
	* unittests/test-rtl.c: New file.
---
 gcc/testsuite/unittests/test-rtl.c | 94 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 94 insertions(+)
 create mode 100644 gcc/testsuite/unittests/test-rtl.c

diff --git a/gcc/testsuite/unittests/test-rtl.c b/gcc/testsuite/unittests/test-rtl.c
new file mode 100644
index 0000000..69eb444
--- /dev/null
+++ b/gcc/testsuite/unittests/test-rtl.c
@@ -0,0 +1,94 @@
+/* Unit tests for RTL-handling.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "gtest/gtest.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "pretty-print.h"
+#include "cfgbuild.h"
+#include "print-rtl.h"
+
+namespace {
+
+class rtl_test : public ::testing::Test
+{
+ protected:
+  void
+  verify_print_pattern (const char *expected, rtx pat)
+  {
+    pretty_printer pp;
+    print_pattern (&pp, pat, 1);
+    EXPECT_STREQ (expected, pp_formatted_text (&pp));
+  }
+};
+
+/* Unit testing of "single_set".  */
+TEST_F (rtl_test, test_single_set)
+{
+  /* A label is not a SET.  */
+  EXPECT_EQ (NULL_RTX, single_set (gen_label_rtx ()));
+
+  /* An unconditional jump insn is a single SET.  */
+  rtx set_pc = gen_rtx_SET (pc_rtx,
+			    gen_rtx_LABEL_REF (VOIDmode,
+					       gen_label_rtx ()));
+  rtx_insn *jump_insn = emit_jump_insn (set_pc);
+  EXPECT_EQ (set_pc, single_set (jump_insn));
+
+  /* etc */
+}
+
+TEST_F (rtl_test, uncond_jump)
+{
+  rtx_insn *label = gen_label_rtx ();
+  rtx jump_pat = gen_rtx_SET (pc_rtx,
+			      gen_rtx_LABEL_REF (VOIDmode,
+						 label));
+  EXPECT_EQ (SET, jump_pat->code);
+  EXPECT_EQ (LABEL_REF, SET_SRC (jump_pat)->code);
+  EXPECT_EQ (label, LABEL_REF_LABEL (SET_SRC (jump_pat)));
+  EXPECT_EQ (PC, SET_DEST (jump_pat)->code);
+
+  verify_print_pattern ("pc=L0", jump_pat);
+
+  rtx_insn *jump_insn = emit_jump_insn (jump_pat);
+  EXPECT_FALSE (any_condjump_p (jump_insn));
+  EXPECT_TRUE (any_uncondjump_p (jump_insn));
+  EXPECT_TRUE (pc_set (jump_insn));
+  EXPECT_TRUE (simplejump_p (jump_insn));
+  EXPECT_TRUE (onlyjump_p (jump_insn));
+  EXPECT_TRUE (control_flow_insn_p (jump_insn));
+}
+
+}  /* anon namespace.  */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 16/16] Add test-wide-int.c to unittests
  2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
                               ` (12 preceding siblings ...)
  2015-10-27 19:50             ` [PATCH 13/16] Add test-rtl.c " David Malcolm
@ 2015-10-27 19:51             ` David Malcolm
  2015-10-30  5:15               ` Jeff Law
  2015-10-27 19:58             ` [PATCH 09/16] Add test-gimple.c " David Malcolm
                               ` (4 subsequent siblings)
  18 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-10-27 19:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/testsuite/ChangeLog:
	* unittests/test-wide-int.c: New file.
---
 gcc/testsuite/unittests/test-wide-int.c | 185 ++++++++++++++++++++++++++++++++
 1 file changed, 185 insertions(+)
 create mode 100644 gcc/testsuite/unittests/test-wide-int.c

diff --git a/gcc/testsuite/unittests/test-wide-int.c b/gcc/testsuite/unittests/test-wide-int.c
new file mode 100644
index 0000000..3f2e36e
--- /dev/null
+++ b/gcc/testsuite/unittests/test-wide-int.c
@@ -0,0 +1,185 @@
+/* Unit tests for wide-int.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "gtest/gtest.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "wide-int-print.h"
+
+namespace {
+
+/* The types we will run the testcases for.  */
+typedef ::testing::Types<wide_int, offset_int, widest_int> implementations;
+
+/* A fixture for running the same tests for all of the wide-int.h types
+   listed in "implementations" above.
+
+   Unfortunately, for some reason gtest reports all of the tests as:
+   of type "<type>":
+     [----------] 2 tests from wide_int_test/0, where TypeParam = <type>
+       (snip)
+     [----------] 2 tests from wide_int_test/0 (0 ms total)
+     [----------] 2 tests from wide_int_test/1, where TypeParam = <type>
+       (snip)
+     [----------] 2 tests from wide_int_test/1 (0 ms total)
+     [----------] 2 tests from wide_int_test/2, where TypeParam = <type>
+       (snip)
+     [----------] 2 tests from wide_int_test/2 (0 ms total)
+*/
+
+template <class VALUE_TYPE>
+class wide_int_test : public ::testing::Test
+{
+ protected:
+  /* Helper function for building a test value.  */
+  VALUE_TYPE from_int (int i);
+};
+
+TYPED_TEST_CASE(wide_int_test, implementations);
+
+/* Specializations of the fixture for each wide-int type.  */
+
+template <>
+wide_int
+wide_int_test <wide_int>::from_int (int i)
+{
+  return wi::shwi (i, 32);
+}
+
+template <>
+offset_int
+wide_int_test <offset_int>::from_int (int i)
+{
+  return offset_int (i);
+}
+
+template <>
+widest_int
+wide_int_test <widest_int>::from_int (int i)
+{
+  return widest_int (i);
+}
+
+/* Verify that print_dec (WI, ..., SGN) gives the expected string
+   representation (using base 10).  */
+
+void
+expect_deceq (const char *expected, const wide_int_ref &wi, signop sgn)
+{
+  char buf[WIDE_INT_PRINT_BUFFER_SIZE];
+  print_dec (wi, buf, sgn);
+  EXPECT_STREQ (expected, buf);
+}
+
+/* Likewise for base 16.  */
+
+void
+expect_hexeq (const char *expected, const wide_int_ref &wi)
+{
+  char buf[WIDE_INT_PRINT_BUFFER_SIZE];
+  print_hex (wi, buf);
+  EXPECT_STREQ (expected, buf);
+}
+
+/* Test cases.  These will be run for each type in "implementations" above,
+   with gtest's TYPED_TEST macro defining the types "TypeParam"
+   and "TestFixture".  */
+
+TYPED_TEST (wide_int_test, test_printing)
+{
+  TypeParam a = TestFixture::from_int (42);
+  expect_deceq ("42", a, SIGNED);
+  expect_hexeq ("0x2a", a);
+}
+
+TYPED_TEST (wide_int_test, test_ops)
+{
+  TypeParam a = TestFixture::from_int (7);
+  TypeParam b = TestFixture::from_int (3);
+
+  /* Using functions.  */
+  expect_deceq ("-7", wi::neg (a), SIGNED);
+  expect_deceq ("10", wi::add (a, b), SIGNED);
+  expect_deceq ("4", wi::sub (a, b), SIGNED);
+  expect_deceq ("-4", wi::sub (b, a), SIGNED);
+  expect_deceq ("21", wi::mul (a, b), SIGNED);
+
+  /* Using operators.  */
+  expect_deceq ("-7", -a, SIGNED);
+  expect_deceq ("10", a + b, SIGNED);
+  expect_deceq ("4", a - b, SIGNED);
+  expect_deceq ("-4", b - a, SIGNED);
+  expect_deceq ("21", a * b, SIGNED);
+}
+
+TYPED_TEST (wide_int_test, test_comparisons)
+{
+  TypeParam a = TestFixture::from_int (7);
+  TypeParam b = TestFixture::from_int (3);
+
+  /* == */
+  EXPECT_TRUE (wi::eq_p (a, a));
+  EXPECT_FALSE (wi::eq_p (a, b));
+
+  /* != */
+  EXPECT_TRUE (wi::ne_p (a, b));
+  EXPECT_FALSE (wi::ne_p (a, a));
+
+  /* < */
+  EXPECT_FALSE (wi::lts_p (a, a));
+  EXPECT_FALSE (wi::lts_p (a, b));
+  EXPECT_TRUE (wi::lts_p (b, a));
+
+  /* <= */
+  EXPECT_TRUE (wi::les_p (a, a));
+  EXPECT_FALSE (wi::les_p (a, b));
+  EXPECT_TRUE (wi::les_p (b, a));
+
+  /* > */
+  EXPECT_FALSE (wi::gts_p (a, a));
+  EXPECT_TRUE (wi::gts_p (a, b));
+  EXPECT_FALSE (wi::gts_p (b, a));
+
+  /* >= */
+  EXPECT_TRUE (wi::ges_p (a, a));
+  EXPECT_TRUE (wi::ges_p (a, b));
+  EXPECT_FALSE (wi::ges_p (b, a));
+
+  /* comparison */
+  EXPECT_EQ (-1, wi::cmps (b, a));
+  EXPECT_EQ (0, wi::cmps (a, a));
+  EXPECT_EQ (1, wi::cmps (a, b));
+}
+
+}  /* anon namespace.  */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 09/16] Add test-gimple.c to unittests
  2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
                               ` (13 preceding siblings ...)
  2015-10-27 19:51             ` [PATCH 16/16] Add test-wide-int.c " David Malcolm
@ 2015-10-27 19:58             ` David Malcolm
  2015-10-28 12:39               ` Richard Biener
  2015-10-30  5:02               ` Jeff Law
  2015-10-27 20:16             ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
                               ` (3 subsequent siblings)
  18 siblings, 2 replies; 176+ messages in thread
From: David Malcolm @ 2015-10-27 19:58 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/testsuite/ChangeLog:
	* unittests/test-gimple.c: New file.
---
 gcc/testsuite/unittests/test-gimple.c | 178 ++++++++++++++++++++++++++++++++++
 1 file changed, 178 insertions(+)
 create mode 100644 gcc/testsuite/unittests/test-gimple.c

diff --git a/gcc/testsuite/unittests/test-gimple.c b/gcc/testsuite/unittests/test-gimple.c
new file mode 100644
index 0000000..b0fa9f4
--- /dev/null
+++ b/gcc/testsuite/unittests/test-gimple.c
@@ -0,0 +1,178 @@
+/* Unit tests for gimple.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "gtest/gtest.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "hard-reg-set.h"
+#include "input.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "gimple-expr.h"
+#include "toplev.h"
+#include "print-tree.h"
+#include "tree-iterator.h"
+#include "gimplify.h"
+#include "tree-cfg.h"
+#include "basic-block.h"
+#include "double-int.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "stmt.h"
+#include "hash-table.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "context.h"
+#include "hash-map.h"
+#include "plugin-api.h"
+#include "ipa-ref.h"
+#include "cgraph.h"
+#include "gimple-pretty-print.h"
+
+namespace {
+
+class gimple_test : public ::testing::Test
+{
+ protected:
+  void
+  verify_gimple_pp (const char *expected, gimple *stmt)
+  {
+    pretty_printer pp;
+    pp_gimple_stmt_1 (&pp, stmt, 0 /* spc */, 0 /* flags */);
+    EXPECT_STREQ (expected, pp_formatted_text (&pp));
+  }
+};
+
+TEST_F (gimple_test, assign_single)
+{
+  /* Build "tmp = 5;"  */
+  tree type = integer_type_node;
+  tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			 get_identifier ("tmp"),
+			 type);
+  tree rhs = build_int_cst (type, 5);
+  gassign *stmt = gimple_build_assign (lhs, rhs);
+  verify_gimple_pp ("tmp = 5;", stmt);
+
+  EXPECT_TRUE (is_gimple_assign (stmt));
+  EXPECT_EQ (lhs, gimple_assign_lhs (stmt));
+  EXPECT_EQ (lhs, gimple_get_lhs (stmt));
+  EXPECT_EQ (rhs, gimple_assign_rhs1 (stmt));
+  EXPECT_EQ (NULL, gimple_assign_rhs2 (stmt));
+  EXPECT_EQ (NULL, gimple_assign_rhs3 (stmt));
+  EXPECT_TRUE (gimple_assign_single_p (stmt));
+  EXPECT_EQ (INTEGER_CST, gimple_assign_rhs_code (stmt));
+}
+
+TEST_F (gimple_test, assign_binop)
+{
+  /* Build "tmp = a + b;"  */
+  tree type = integer_type_node;
+  tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			 get_identifier ("tmp"),
+			 type);
+  tree a = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		       get_identifier ("a"),
+		       type);
+  tree b = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		       get_identifier ("b"),
+		       type);
+  gassign *stmt = gimple_build_assign (lhs, MULT_EXPR, a, b);
+  verify_gimple_pp ("tmp = a * b;", stmt);
+
+  EXPECT_TRUE (is_gimple_assign (stmt));
+  EXPECT_EQ (lhs, gimple_assign_lhs (stmt));
+  EXPECT_EQ (lhs, gimple_get_lhs (stmt));
+  EXPECT_EQ (a, gimple_assign_rhs1 (stmt));
+  EXPECT_EQ (b, gimple_assign_rhs2 (stmt));
+  EXPECT_EQ (NULL, gimple_assign_rhs3 (stmt));
+  EXPECT_FALSE (gimple_assign_single_p (stmt));
+  EXPECT_EQ (MULT_EXPR, gimple_assign_rhs_code (stmt));
+}
+
+TEST_F (gimple_test, nop_stmt)
+{
+  gimple *stmt = gimple_build_nop ();
+  verify_gimple_pp ("GIMPLE_NOP", stmt);
+  EXPECT_EQ (GIMPLE_NOP, gimple_code (stmt));
+  EXPECT_EQ (NULL, gimple_get_lhs (stmt));
+  EXPECT_FALSE (gimple_assign_single_p (stmt));
+}
+
+TEST_F (gimple_test, return_stmt)
+{
+  /* Build "return 7;"  */
+  tree type = integer_type_node;
+  tree val = build_int_cst (type, 7);
+  greturn *stmt = gimple_build_return (val);
+  verify_gimple_pp ("return 7;", stmt);
+
+  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt));
+  EXPECT_EQ (NULL, gimple_get_lhs (stmt));
+  EXPECT_EQ (val, gimple_return_retval (stmt));
+  EXPECT_FALSE (gimple_assign_single_p (stmt));
+}
+
+TEST_F (gimple_test, return_without_value)
+{
+  greturn *stmt = gimple_build_return (NULL);
+  verify_gimple_pp ("return;", stmt);
+
+  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt));
+  EXPECT_EQ (NULL, gimple_get_lhs (stmt));
+  EXPECT_EQ (NULL, gimple_return_retval (stmt));
+  EXPECT_FALSE (gimple_assign_single_p (stmt));
+}
+
+}  /* anon namespace.  */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/16] Unit tests framework (v3)
  2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
                               ` (14 preceding siblings ...)
  2015-10-27 19:58             ` [PATCH 09/16] Add test-gimple.c " David Malcolm
@ 2015-10-27 20:16             ` David Malcolm
  2015-10-30  5:28               ` Jeff Law
  2015-10-28 11:53             ` Bernd Schmidt
                               ` (2 subsequent siblings)
  18 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-10-27 20:16 UTC (permalink / raw)
  To: gcc-patches

On Tue, 2015-10-27 at 15:48 -0400, David Malcolm wrote:
[...snip...]

Looks like [Patch 02/16] was too big (1.2MB) for the list;
it can be seen here:
https://dmalcolm.fedorapeople.org/gcc/2015-10-27/unittests/0002-Add-embedded-copy-of-gtest-1.7-to-unittests.patch

[..snip...]


^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/16] Unit tests framework (v3)
  2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
                               ` (15 preceding siblings ...)
  2015-10-27 20:16             ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
@ 2015-10-28 11:53             ` Bernd Schmidt
  2015-10-28 13:02               ` Bernd Schmidt
                                 ` (2 more replies)
  2015-10-28 16:05             ` [PATCH 00/16] Unit tests framework (v3) Jeff Law
  2015-10-28 20:26             ` Mike Stump
  18 siblings, 3 replies; 176+ messages in thread
From: Bernd Schmidt @ 2015-10-28 11:53 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/27/2015 08:48 PM, David Malcolm wrote:
> The following patch kit adds a unit tests framework for gcc,
> as a new subdirectory below gcc/testsuite.

So, as a general comment I think this would be a very good thing to 
have, and from a quick look through the tests they look pretty sensible.

> Like previous versions of the patch kit it uses the Google Test
> framework, since I've had good experiences with it:
>    http://code.google.com/p/googletest/
> and like v2 of the kit it embeds a two-file copy of v1.7 of
> the kit, to avoid adding extra dependencies (one .h file and one
> .c file).

How much of this are you actually using? How much effort would be 
involved in removing the extra prerequisite? Is it just the EXPECT_TRUE 
etc. macros?

> v1 of the kit was structured as a frontend, v2 of the kit as
> a plugin that was built as if it were a frontend.  Both of
> these approaches were problematic, so this version
> of the patch kit simply builds as a test case within the
> plugin.exp suites.

This is the part I'm least certain about, for two reasons:
  * They are more like source files than tests, and I think I'd prefer
    to have them alongside the source, in gcc/ rather than in the
    testsuite. This way people are invariable going to fail to notice
    them when they grep for something.
  * This uses a plugin into whatever compiler was built, but sometimes
    you can't really set up unit tests that way because what you want
    to test depends on target specifics. What I've often wanted is a
    special test target that gets built with a special machine
    description that has whatever patterns are needed to replicate
    tricky situations in reload or other optimization passes.

The tests you have so far are focused mostly on high-level gimple/tree 
tests where this limitation is probably not showing up very much, but I 
think it would be better to have something that allows us to have more 
in-depth tests.


Bernd

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 09/16] Add test-gimple.c to unittests
  2015-10-27 19:58             ` [PATCH 09/16] Add test-gimple.c " David Malcolm
@ 2015-10-28 12:39               ` Richard Biener
  2015-10-28 12:44                 ` Richard Biener
  2015-10-30  5:02               ` Jeff Law
  1 sibling, 1 reply; 176+ messages in thread
From: Richard Biener @ 2015-10-28 12:39 UTC (permalink / raw)
  To: David Malcolm; +Cc: GCC Patches

On Tue, Oct 27, 2015 at 8:49 PM, David Malcolm <dmalcolm@redhat.com> wrote:
> gcc/testsuite/ChangeLog:
>         * unittests/test-gimple.c: New file.

I fear that keeping tests like this up-to-date and working is more of
a headache than
the value we get from it.

Richard.

> ---
>  gcc/testsuite/unittests/test-gimple.c | 178 ++++++++++++++++++++++++++++++++++
>  1 file changed, 178 insertions(+)
>  create mode 100644 gcc/testsuite/unittests/test-gimple.c
>
> diff --git a/gcc/testsuite/unittests/test-gimple.c b/gcc/testsuite/unittests/test-gimple.c
> new file mode 100644
> index 0000000..b0fa9f4
> --- /dev/null
> +++ b/gcc/testsuite/unittests/test-gimple.c
> @@ -0,0 +1,178 @@
> +/* Unit tests for gimple.
> +   Copyright (C) 2015 Free Software Foundation, Inc.
> +
> +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 "config.h"
> +#include "gtest/gtest.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "tm.h"
> +#include "opts.h"
> +#include "signop.h"
> +#include "hash-set.h"
> +#include "fixed-value.h"
> +#include "alias.h"
> +#include "flags.h"
> +#include "symtab.h"
> +#include "tree-core.h"
> +#include "stor-layout.h"
> +#include "tree.h"
> +#include "stringpool.h"
> +#include "stor-layout.h"
> +#include "rtl.h"
> +#include "predict.h"
> +#include "vec.h"
> +#include "hashtab.h"
> +#include "hash-set.h"
> +#include "machmode.h"
> +#include "hard-reg-set.h"
> +#include "input.h"
> +#include "function.h"
> +#include "dominance.h"
> +#include "cfg.h"
> +#include "cfganal.h"
> +#include "basic-block.h"
> +#include "tree-ssa-alias.h"
> +#include "internal-fn.h"
> +#include "gimple-fold.h"
> +#include "gimple-expr.h"
> +#include "toplev.h"
> +#include "print-tree.h"
> +#include "tree-iterator.h"
> +#include "gimplify.h"
> +#include "tree-cfg.h"
> +#include "basic-block.h"
> +#include "double-int.h"
> +#include "alias.h"
> +#include "symtab.h"
> +#include "wide-int.h"
> +#include "inchash.h"
> +#include "tree.h"
> +#include "fold-const.h"
> +#include "stor-layout.h"
> +#include "stmt.h"
> +#include "hash-table.h"
> +#include "tree-ssa-alias.h"
> +#include "internal-fn.h"
> +#include "gimple-expr.h"
> +#include "is-a.h"
> +#include "gimple.h"
> +#include "tree-pass.h"
> +#include "context.h"
> +#include "hash-map.h"
> +#include "plugin-api.h"
> +#include "ipa-ref.h"
> +#include "cgraph.h"
> +#include "gimple-pretty-print.h"
> +
> +namespace {
> +
> +class gimple_test : public ::testing::Test
> +{
> + protected:
> +  void
> +  verify_gimple_pp (const char *expected, gimple *stmt)
> +  {
> +    pretty_printer pp;
> +    pp_gimple_stmt_1 (&pp, stmt, 0 /* spc */, 0 /* flags */);
> +    EXPECT_STREQ (expected, pp_formatted_text (&pp));
> +  }
> +};
> +
> +TEST_F (gimple_test, assign_single)
> +{
> +  /* Build "tmp = 5;"  */
> +  tree type = integer_type_node;
> +  tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL,
> +                        get_identifier ("tmp"),
> +                        type);
> +  tree rhs = build_int_cst (type, 5);
> +  gassign *stmt = gimple_build_assign (lhs, rhs);
> +  verify_gimple_pp ("tmp = 5;", stmt);
> +
> +  EXPECT_TRUE (is_gimple_assign (stmt));
> +  EXPECT_EQ (lhs, gimple_assign_lhs (stmt));
> +  EXPECT_EQ (lhs, gimple_get_lhs (stmt));
> +  EXPECT_EQ (rhs, gimple_assign_rhs1 (stmt));
> +  EXPECT_EQ (NULL, gimple_assign_rhs2 (stmt));
> +  EXPECT_EQ (NULL, gimple_assign_rhs3 (stmt));
> +  EXPECT_TRUE (gimple_assign_single_p (stmt));
> +  EXPECT_EQ (INTEGER_CST, gimple_assign_rhs_code (stmt));
> +}
> +
> +TEST_F (gimple_test, assign_binop)
> +{
> +  /* Build "tmp = a + b;"  */
> +  tree type = integer_type_node;
> +  tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL,
> +                        get_identifier ("tmp"),
> +                        type);
> +  tree a = build_decl (UNKNOWN_LOCATION, VAR_DECL,
> +                      get_identifier ("a"),
> +                      type);
> +  tree b = build_decl (UNKNOWN_LOCATION, VAR_DECL,
> +                      get_identifier ("b"),
> +                      type);
> +  gassign *stmt = gimple_build_assign (lhs, MULT_EXPR, a, b);
> +  verify_gimple_pp ("tmp = a * b;", stmt);
> +
> +  EXPECT_TRUE (is_gimple_assign (stmt));
> +  EXPECT_EQ (lhs, gimple_assign_lhs (stmt));
> +  EXPECT_EQ (lhs, gimple_get_lhs (stmt));
> +  EXPECT_EQ (a, gimple_assign_rhs1 (stmt));
> +  EXPECT_EQ (b, gimple_assign_rhs2 (stmt));
> +  EXPECT_EQ (NULL, gimple_assign_rhs3 (stmt));
> +  EXPECT_FALSE (gimple_assign_single_p (stmt));
> +  EXPECT_EQ (MULT_EXPR, gimple_assign_rhs_code (stmt));
> +}
> +
> +TEST_F (gimple_test, nop_stmt)
> +{
> +  gimple *stmt = gimple_build_nop ();
> +  verify_gimple_pp ("GIMPLE_NOP", stmt);
> +  EXPECT_EQ (GIMPLE_NOP, gimple_code (stmt));
> +  EXPECT_EQ (NULL, gimple_get_lhs (stmt));
> +  EXPECT_FALSE (gimple_assign_single_p (stmt));
> +}
> +
> +TEST_F (gimple_test, return_stmt)
> +{
> +  /* Build "return 7;"  */
> +  tree type = integer_type_node;
> +  tree val = build_int_cst (type, 7);
> +  greturn *stmt = gimple_build_return (val);
> +  verify_gimple_pp ("return 7;", stmt);
> +
> +  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt));
> +  EXPECT_EQ (NULL, gimple_get_lhs (stmt));
> +  EXPECT_EQ (val, gimple_return_retval (stmt));
> +  EXPECT_FALSE (gimple_assign_single_p (stmt));
> +}
> +
> +TEST_F (gimple_test, return_without_value)
> +{
> +  greturn *stmt = gimple_build_return (NULL);
> +  verify_gimple_pp ("return;", stmt);
> +
> +  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt));
> +  EXPECT_EQ (NULL, gimple_get_lhs (stmt));
> +  EXPECT_EQ (NULL, gimple_return_retval (stmt));
> +  EXPECT_FALSE (gimple_assign_single_p (stmt));
> +}
> +
> +}  /* anon namespace.  */
> --
> 1.8.5.3
>

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 09/16] Add test-gimple.c to unittests
  2015-10-28 12:39               ` Richard Biener
@ 2015-10-28 12:44                 ` Richard Biener
  2015-10-28 16:22                   ` Jeff Law
  0 siblings, 1 reply; 176+ messages in thread
From: Richard Biener @ 2015-10-28 12:44 UTC (permalink / raw)
  To: David Malcolm; +Cc: GCC Patches

On Wed, Oct 28, 2015 at 1:34 PM, Richard Biener
<richard.guenther@gmail.com> wrote:
> On Tue, Oct 27, 2015 at 8:49 PM, David Malcolm <dmalcolm@redhat.com> wrote:
>> gcc/testsuite/ChangeLog:
>>         * unittests/test-gimple.c: New file.
>
> I fear that keeping tests like this up-to-date and working is more of
> a headache than
> the value we get from it.

So - with our testsuite and passes we have the issues that we'd like
to have regression
tests that nail down the IL input to a specific pass.  That rots over
time (obviously) so
many tests are no longer testing what they are supposed to test.

Some years ago I proposed -Otest to make the input into passes a little bit more
stable (basically run only a single pass).  It requires the desired
pass input to
be created from the lowering stages only of course (you could enable more than
one pass but then things get less stable again).

Ideally we'd get progress with the GIMPLE FE up to the point that textual
input to passes works (we need pass manager support for this as well,
of course).

I'm fine with doing your kind of unit tests for infrastructure things,
but test-gimple.c at
least looks very odd.

Richard.

> Richard.
>
>> ---
>>  gcc/testsuite/unittests/test-gimple.c | 178 ++++++++++++++++++++++++++++++++++
>>  1 file changed, 178 insertions(+)
>>  create mode 100644 gcc/testsuite/unittests/test-gimple.c
>>
>> diff --git a/gcc/testsuite/unittests/test-gimple.c b/gcc/testsuite/unittests/test-gimple.c
>> new file mode 100644
>> index 0000000..b0fa9f4
>> --- /dev/null
>> +++ b/gcc/testsuite/unittests/test-gimple.c
>> @@ -0,0 +1,178 @@
>> +/* Unit tests for gimple.
>> +   Copyright (C) 2015 Free Software Foundation, Inc.
>> +
>> +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 "config.h"
>> +#include "gtest/gtest.h"
>> +#include "system.h"
>> +#include "coretypes.h"
>> +#include "tm.h"
>> +#include "opts.h"
>> +#include "signop.h"
>> +#include "hash-set.h"
>> +#include "fixed-value.h"
>> +#include "alias.h"
>> +#include "flags.h"
>> +#include "symtab.h"
>> +#include "tree-core.h"
>> +#include "stor-layout.h"
>> +#include "tree.h"
>> +#include "stringpool.h"
>> +#include "stor-layout.h"
>> +#include "rtl.h"
>> +#include "predict.h"
>> +#include "vec.h"
>> +#include "hashtab.h"
>> +#include "hash-set.h"
>> +#include "machmode.h"
>> +#include "hard-reg-set.h"
>> +#include "input.h"
>> +#include "function.h"
>> +#include "dominance.h"
>> +#include "cfg.h"
>> +#include "cfganal.h"
>> +#include "basic-block.h"
>> +#include "tree-ssa-alias.h"
>> +#include "internal-fn.h"
>> +#include "gimple-fold.h"
>> +#include "gimple-expr.h"
>> +#include "toplev.h"
>> +#include "print-tree.h"
>> +#include "tree-iterator.h"
>> +#include "gimplify.h"
>> +#include "tree-cfg.h"
>> +#include "basic-block.h"
>> +#include "double-int.h"
>> +#include "alias.h"
>> +#include "symtab.h"
>> +#include "wide-int.h"
>> +#include "inchash.h"
>> +#include "tree.h"
>> +#include "fold-const.h"
>> +#include "stor-layout.h"
>> +#include "stmt.h"
>> +#include "hash-table.h"
>> +#include "tree-ssa-alias.h"
>> +#include "internal-fn.h"
>> +#include "gimple-expr.h"
>> +#include "is-a.h"
>> +#include "gimple.h"
>> +#include "tree-pass.h"
>> +#include "context.h"
>> +#include "hash-map.h"
>> +#include "plugin-api.h"
>> +#include "ipa-ref.h"
>> +#include "cgraph.h"
>> +#include "gimple-pretty-print.h"
>> +
>> +namespace {
>> +
>> +class gimple_test : public ::testing::Test
>> +{
>> + protected:
>> +  void
>> +  verify_gimple_pp (const char *expected, gimple *stmt)
>> +  {
>> +    pretty_printer pp;
>> +    pp_gimple_stmt_1 (&pp, stmt, 0 /* spc */, 0 /* flags */);
>> +    EXPECT_STREQ (expected, pp_formatted_text (&pp));
>> +  }
>> +};
>> +
>> +TEST_F (gimple_test, assign_single)
>> +{
>> +  /* Build "tmp = 5;"  */
>> +  tree type = integer_type_node;
>> +  tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL,
>> +                        get_identifier ("tmp"),
>> +                        type);
>> +  tree rhs = build_int_cst (type, 5);
>> +  gassign *stmt = gimple_build_assign (lhs, rhs);
>> +  verify_gimple_pp ("tmp = 5;", stmt);
>> +
>> +  EXPECT_TRUE (is_gimple_assign (stmt));
>> +  EXPECT_EQ (lhs, gimple_assign_lhs (stmt));
>> +  EXPECT_EQ (lhs, gimple_get_lhs (stmt));
>> +  EXPECT_EQ (rhs, gimple_assign_rhs1 (stmt));
>> +  EXPECT_EQ (NULL, gimple_assign_rhs2 (stmt));
>> +  EXPECT_EQ (NULL, gimple_assign_rhs3 (stmt));
>> +  EXPECT_TRUE (gimple_assign_single_p (stmt));
>> +  EXPECT_EQ (INTEGER_CST, gimple_assign_rhs_code (stmt));
>> +}
>> +
>> +TEST_F (gimple_test, assign_binop)
>> +{
>> +  /* Build "tmp = a + b;"  */
>> +  tree type = integer_type_node;
>> +  tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL,
>> +                        get_identifier ("tmp"),
>> +                        type);
>> +  tree a = build_decl (UNKNOWN_LOCATION, VAR_DECL,
>> +                      get_identifier ("a"),
>> +                      type);
>> +  tree b = build_decl (UNKNOWN_LOCATION, VAR_DECL,
>> +                      get_identifier ("b"),
>> +                      type);
>> +  gassign *stmt = gimple_build_assign (lhs, MULT_EXPR, a, b);
>> +  verify_gimple_pp ("tmp = a * b;", stmt);
>> +
>> +  EXPECT_TRUE (is_gimple_assign (stmt));
>> +  EXPECT_EQ (lhs, gimple_assign_lhs (stmt));
>> +  EXPECT_EQ (lhs, gimple_get_lhs (stmt));
>> +  EXPECT_EQ (a, gimple_assign_rhs1 (stmt));
>> +  EXPECT_EQ (b, gimple_assign_rhs2 (stmt));
>> +  EXPECT_EQ (NULL, gimple_assign_rhs3 (stmt));
>> +  EXPECT_FALSE (gimple_assign_single_p (stmt));
>> +  EXPECT_EQ (MULT_EXPR, gimple_assign_rhs_code (stmt));
>> +}
>> +
>> +TEST_F (gimple_test, nop_stmt)
>> +{
>> +  gimple *stmt = gimple_build_nop ();
>> +  verify_gimple_pp ("GIMPLE_NOP", stmt);
>> +  EXPECT_EQ (GIMPLE_NOP, gimple_code (stmt));
>> +  EXPECT_EQ (NULL, gimple_get_lhs (stmt));
>> +  EXPECT_FALSE (gimple_assign_single_p (stmt));
>> +}
>> +
>> +TEST_F (gimple_test, return_stmt)
>> +{
>> +  /* Build "return 7;"  */
>> +  tree type = integer_type_node;
>> +  tree val = build_int_cst (type, 7);
>> +  greturn *stmt = gimple_build_return (val);
>> +  verify_gimple_pp ("return 7;", stmt);
>> +
>> +  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt));
>> +  EXPECT_EQ (NULL, gimple_get_lhs (stmt));
>> +  EXPECT_EQ (val, gimple_return_retval (stmt));
>> +  EXPECT_FALSE (gimple_assign_single_p (stmt));
>> +}
>> +
>> +TEST_F (gimple_test, return_without_value)
>> +{
>> +  greturn *stmt = gimple_build_return (NULL);
>> +  verify_gimple_pp ("return;", stmt);
>> +
>> +  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt));
>> +  EXPECT_EQ (NULL, gimple_get_lhs (stmt));
>> +  EXPECT_EQ (NULL, gimple_return_retval (stmt));
>> +  EXPECT_FALSE (gimple_assign_single_p (stmt));
>> +}
>> +
>> +}  /* anon namespace.  */
>> --
>> 1.8.5.3
>>

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/16] Unit tests framework (v3)
  2015-10-28 11:53             ` Bernd Schmidt
@ 2015-10-28 13:02               ` Bernd Schmidt
  2015-10-29 16:20               ` David Malcolm
  2015-10-29 19:21               ` Jeff Law
  2 siblings, 0 replies; 176+ messages in thread
From: Bernd Schmidt @ 2015-10-28 13:02 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/28/2015 12:38 PM, Bernd Schmidt wrote:
>   * This uses a plugin into whatever compiler was built, but sometimes
>     you can't really set up unit tests that way because what you want
>     to test depends on target specifics. What I've often wanted is a
>     special test target that gets built with a special machine
>     description that has whatever patterns are needed to replicate
>     tricky situations in reload or other optimization passes.

Continuing to think out loud, this could be built in a separate 
top-level directory alongside the normal build. We've briefly had 
machinery to do something like that for OpenACC accel-gcc builds; that 
was removed but it shows that the concept is viable.

We should ensure that our framework for this is powerful enough to 
validate not just basic data structures like wide-int, but also 
questions like "I just set up an rtl insn in a specific way, does it 
produce the right set of reloads?"


Bernd

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/16] Unit tests framework (v3)
  2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
                               ` (16 preceding siblings ...)
  2015-10-28 11:53             ` Bernd Schmidt
@ 2015-10-28 16:05             ` Jeff Law
  2015-10-28 20:26             ` Mike Stump
  18 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-10-28 16:05 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/27/2015 01:48 PM, David Malcolm wrote:
> This is a followup to these proposals:
>   * v1: https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00765.html
>   * v2: https://gcc.gnu.org/ml/gcc-patches/2015-06/msg01224.html
>
> The following patch kit adds a unit tests framework for gcc,
> as a new subdirectory below gcc/testsuite.
>
> The aim is to give us direct coverage of low level implementation
> details that aren't well covered by our existing tests, such as
> our data structures, gengtype, etc.  This will let us have tests
> that directly poke at specific internal APIs and verify that the
> right thing happens, rather than having to write source code and
> option combinations that we hope touches the relevant state.
> It should make it trivial to add new unit tests.
>
> I see it as complementary to our existing test approaches.
Right.  And I feel I ought to chime in since I've been the source of 
confusion WRT unit testing.  I have often mis-used the term "unit 
testing" to mean feed state/code into a pass and test what comes out.

But that's not actually unit testing and not the focus of this patchkit 
from David.  As David states, the idea here is to get direct testing 
coverage of low level internals.   I've been pondering this problem a 
fair amount lately as I look at our codebase and ponder how to improve 
its maintainability over time.

This kind of low level testing has value.  I don't doubt that in the 
slightest anymore.  I fear the real problem in this space is getting 
enough scaffolding around those low level things we want to test so that 
we can write tests around them.  I wouldn't at all be surprised if we go 
through multiple iterations on the overall design & implementation. 
Hell, you're already on your 3rd :-)


>
> Like previous versions of the patch kit it uses the Google Test
> framework, since I've had good experiences with it:
>    http://code.google.com/p/googletest/
> and like v2 of the kit it embeds a two-file copy of v1.7 of
> the kit, to avoid adding extra dependencies (one .h file and one
> .c file).
>
> v1 of the kit was structured as a frontend, v2 of the kit as
> a plugin that was built as if it were a frontend.  Both of
> these approaches were problematic, so this version
> of the patch kit simply builds as a test case within the
> plugin.exp suites.
Using a plugin approach allows us to avoid at least some of the problems 
in getting a test that can be built because ultimately the bits get 
sucked into the address space of the compiler as a DSO.

I suspect that's the only sensible model in the short/medium term.  I 
just don't see us getting to a point where (for example) we could 
instantiate some internal class as an independent test totally 
independent of the rest of the compiler without a ton more work.

I will note that large blobs of what Andrew has been doing would be a 
prerequisite for getting to that point.

Anyway, it's a bit of rambling, but in the end, I think the summary is 
the plugin approach seems right for where we are today and expect to be 
for a while.


>
> In this approach, each of gcc.dg and g++.dg have a plugin.exp that
> lists plugins to be built and source files to then compile with
> the plugin.  This patch kit inserts into them references to the plugin
> within ../../unittests, so that we can run the tests within both cc1
> and cc1plus without having to list everything twice.  The plugin
> is built by plugin.exp and plugin-support.exp as per the existing
> test cases.  Doing so requires #include-ing everything relevant
> within unittests-plugin.c.
So as I ponder how we'll use this in practice, I think we'll probably 
need a way to control which tests run with a fair amount of granularity. 
  So for example, if I'm doing something like cleaning up the SSA_NAME 
manager, I'd really like to be able to unit test that and do so quickly 
& repeatedly during development before moving on to a larger test like 
bootstrap & regression test.  Similarly if I had this framework in place 
earlier, I would have wanted run tests around just the scoped hashtable 
interface and implementation.

Conceptually this might work in the same manner we've done with 
c-torture & the dg frameworks.  ie

RUNTESTFLAGS=unittest.exp=scopedtables

If you've already got that capability in place, then well, that's awesome.


>
> The plugin uses a custom gtest reporter that reports results in
> DejaGnu format.  The kit adds some logic to testsuite/lib/prune.exp
> to parse the DejaGnu output on stderr e.g.:
>    PASS: ggc_test.inheritance
> and re-emits it at the Tcl level, so that the unit test results from
> the plugin are reported within the regular test output like this:
>    PASS: gcc.dg/plugin/unittests.c -fplugin=./unittests-plugin.so  ggc_test.inheritance
I hate to note it, but isn't the pruning code fairly performance 
sensitive?  Any way to do this outside of prune.exp that doesn't effect 
running the rest of the testsuite?  Or show that it just "doesn't 
matter" having these extra bits in the pruning code.



> Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu
> (on top of r229364); adds 61 new PASS results to each of gcc.sum and
> g++.sum.
>
> I've broken up the patches into logical chunks in the hope of making
> review easier, but this is effectively one change, and would be
> committed as such.  Though if any individual testcases are
> problematic, they could be deferred, if that will help get the rest
> of the work approved.
You know me.  I always try to carve off the easiest parts of the review 
first, then iterate on what's left.  It's usually the case that each 
iteration makes something in the next iteration easier to understand.

So you should expect reviews to arrive in a semi-random order.


>
> [There are some FIXMEs in the testcases indicating room for further
> testing, and I've not fully reduced the #includes in them; is the
> "blessed" #include order documented yet, and do we have tooling
> in "contrib" for this yet?]
The tooling isn't finished, but the last patch from Andrew has usable 
versions.  I've used show-headers extensively, but order-headers and 
reduce/replace seem to work when I've done light poking.  I'd certainly 
recommend using them for the reduction.


Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 09/16] Add test-gimple.c to unittests
  2015-10-28 12:44                 ` Richard Biener
@ 2015-10-28 16:22                   ` Jeff Law
  0 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-10-28 16:22 UTC (permalink / raw)
  To: Richard Biener, David Malcolm; +Cc: GCC Patches

On 10/28/2015 06:39 AM, Richard Biener wrote:
> On Wed, Oct 28, 2015 at 1:34 PM, Richard Biener
> <richard.guenther@gmail.com> wrote:
>> On Tue, Oct 27, 2015 at 8:49 PM, David Malcolm
>> <dmalcolm@redhat.com> wrote:
>>> gcc/testsuite/ChangeLog: * unittests/test-gimple.c: New file.
>>
>> I fear that keeping tests like this up-to-date and working is more
>> of a headache than the value we get from it.
Perhaps.  I'm not sure either way on that specific example.  It might be 
more interesting to do something like that for RTL which doesn't have as 
much static structure.  And it'd provide a basis for testing code to 
bring more static structure to RTL.

>
> So - with our testsuite and passes we have the issues that we'd like
> to have regression tests that nail down the IL input to a specific
> pass.  That rots over time (obviously) so many tests are no longer
> testing what they are supposed to test.
Yes, absolutely.  But I think that class of problems it outside the 
scope of what David is trying to tackle.

Essentially this kind of testing would be a good replacement for most of 
the dump-scanning tests we have.


>
> Some years ago I proposed -Otest to make the input into passes a
> little bit more stable (basically run only a single pass).  It
> requires the desired pass input to be created from the lowering
> stages only of course (you could enable more than one pass but then
> things get less stable again).
I must have missed that.  But it's an interesting idea.

>
> Ideally we'd get progress with the GIMPLE FE up to the point that
> textual input to passes works (we need pass manager support for this
> as well, of course).
We haven't really started planning for next year yet within Red Hat, but 
pushing the gimple front-end has already been mentioned at least once as 
a potential project.


Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/16] Unit tests framework (v3)
  2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
                               ` (17 preceding siblings ...)
  2015-10-28 16:05             ` [PATCH 00/16] Unit tests framework (v3) Jeff Law
@ 2015-10-28 20:26             ` Mike Stump
  18 siblings, 0 replies; 176+ messages in thread
From: Mike Stump @ 2015-10-28 20:26 UTC (permalink / raw)
  To: gcc-patches List; +Cc: David Malcolm

On Oct 27, 2015, at 12:48 PM, David Malcolm <dmalcolm@redhat.com> wrote:
> The following patch kit adds a unit tests framework for gcc,

I’m supportive of the patch set and the concept in general.  I don’t know who wants to review this, Jeff seems on track to do this.  My only guidance would be to say we should allow more latitude and leeway here and let people experiment in tree with what works and what doesn’t and evolve things as fast as they want.  As the patches go in, I think they should have to latitude to evolve things as they see fit.  If they would like to be listed as maintainer of unit test, I’d support that.

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/16] Unit tests framework (v3)
  2015-10-28 11:53             ` Bernd Schmidt
  2015-10-28 13:02               ` Bernd Schmidt
@ 2015-10-29 16:20               ` David Malcolm
  2015-10-29 19:38                 ` Jeff Law
  2015-10-29 19:21               ` Jeff Law
  2 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-10-29 16:20 UTC (permalink / raw)
  To: Bernd Schmidt; +Cc: gcc-patches

On Wed, 2015-10-28 at 12:38 +0100, Bernd Schmidt wrote:
> On 10/27/2015 08:48 PM, David Malcolm wrote:
> > The following patch kit adds a unit tests framework for gcc,
> > as a new subdirectory below gcc/testsuite.
> 
> So, as a general comment I think this would be a very good thing to 
> have, and from a quick look through the tests they look pretty sensible.

Thanks.

> > Like previous versions of the patch kit it uses the Google Test
> > framework, since I've had good experiences with it:
> >    http://code.google.com/p/googletest/
> > and like v2 of the kit it embeds a two-file copy of v1.7 of
> > the kit, to avoid adding extra dependencies (one .h file and one
> > .c file).
> 
> How much of this are you actually using? How much effort would be 
> involved in removing the extra prerequisite? Is it just the EXPECT_TRUE 
> etc. macros?

As well as the EXPECT_FOO macros, there's test registration, sometimes
done via TEST, sometimes via TEST_F to support fixtures.  I used
TYPED_TEST for type-parameterizing the wide-int tests (though, to be
fair, I didn't manage to get this properly working; see the comment in
test-wide-int.c).

There may be useful things in gtest for us that I'm not using yet.  For
example, the support for death tests may be useful for testing that e.g.
our checking macros kill the program sanely in the presence of malformed
internal data.

I wanted to reuse the gtest code on the grounds that:

  * the code exists

  * it's maintained (https://github.com/google/googletest
    shows the last commit was 10 days ago)

  * it has documentation:
https://github.com/google/googletest/blob/master/googletest/docs/Primer.md
(there's much more that just that)

  * it will be familiar to some people from other projects


That said, if it's a blocker, I can attempt a minimal reimplementation
of the subset of the API that I'm using.


One wart in the v3 patchkit was that I used the default configuration
for gtest.  For example, this implicitly required threading support.
This could be suppressed by defining:

   #define GTEST_HAS_PTHREAD 0

before including gtest.h.

> > v1 of the kit was structured as a frontend, v2 of the kit as
> > a plugin that was built as if it were a frontend.  Both of
> > these approaches were problematic, so this version
> > of the patch kit simply builds as a test case within the
> > plugin.exp suites.
> 
> This is the part I'm least certain about, for two reasons:
>   * They are more like source files than tests, and I think I'd prefer
>     to have them alongside the source, in gcc/ rather than in the
>     testsuite. This way people are invariable going to fail to notice
>     them when they grep for something.

So something like:

  gcc/test-vec.c

or even:

  gcc/vec-tests.c

so that it sorts next to gcc/vec.h in a listing?

i.e.   gcc/FOO-tests.c  for gcc/FOO.c

Maybe the unittests-plugin.c should live within the "gcc" directory?

>   * This uses a plugin into whatever compiler was built, but sometimes
>     you can't really set up unit tests that way because what you want
>     to test depends on target specifics. What I've often wanted is a
>     special test target that gets built with a special machine
>     description that has whatever patterns are needed to replicate
>     tricky situations in reload or other optimization passes.
> 
> The tests you have so far are focused mostly on high-level gimple/tree 
> tests where this limitation is probably not showing up very much, but I 
> think it would be better to have something that allows us to have more 
> in-depth tests.

I think our long-term goal should be at least 5 styles of test:

(A) end-to-end tests of the compiler: running it on some source and
verifying properties of the diagnostics and/or generated code
(potentially running it).  This is what we have today.

(B) unit tests of individual subsystems: tests that exercise specific
internal APIs e.g. containers like vec<>, hash_map<> etc, also things
like gengtype.  This is a gap in our current test coverage, and what
this patch kit aims to start filling.

(C) and (D): tests of specific passes: tests that accept IR (either
gimple or RTL), and run just one pass, and verify properties of the IR
emitted by the pass, or messages emitted by the pass.  LLVM has a "-R"
remark option, so that a pass can issue remarks about what it's doing (a
new kind of diagnostic):

http://llvm.org/releases/3.5.0/tools/clang/docs/UsersManual.html#opt-rpass

We could implement this kind of testing by implementing gimple and RTL
frontends, and a -R option, which could integrate nicely with DejaGnu,
with
  /* { dg-remark "inlined here" } */
and the like.

This would require finishing the gimple FE, and writing an RTL FE
(independent goals).  Hopefully that would give us test coverage for
dealing with e.g. tricky reload situations.

(E) performance testing


The purpose of this patch kit is (B).  I'm interested in tackling (C)
and (D), but I think those are going to have to wait until next stage 1
at this point.


Dave

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/16] Unit tests framework (v3)
  2015-10-28 11:53             ` Bernd Schmidt
  2015-10-28 13:02               ` Bernd Schmidt
  2015-10-29 16:20               ` David Malcolm
@ 2015-10-29 19:21               ` Jeff Law
  2015-10-30 10:54                 ` Bernd Schmidt
  2 siblings, 1 reply; 176+ messages in thread
From: Jeff Law @ 2015-10-29 19:21 UTC (permalink / raw)
  To: Bernd Schmidt, David Malcolm, gcc-patches

On 10/28/2015 05:38 AM, Bernd Schmidt wrote:
> On 10/27/2015 08:48 PM, David Malcolm wrote:
>> The following patch kit adds a unit tests framework for gcc,
>> as a new subdirectory below gcc/testsuite.
>
> So, as a general comment I think this would be a very good thing to
> have, and from a quick look through the tests they look pretty sensible.
>
>> Like previous versions of the patch kit it uses the Google Test
>> framework, since I've had good experiences with it:
>>    http://code.google.com/p/googletest/
>> and like v2 of the kit it embeds a two-file copy of v1.7 of
>> the kit, to avoid adding extra dependencies (one .h file and one
>> .c file).
>
> How much of this are you actually using? How much effort would be
> involved in removing the extra prerequisite? Is it just the EXPECT_TRUE
> etc. macros?
>
>> v1 of the kit was structured as a frontend, v2 of the kit as
>> a plugin that was built as if it were a frontend.  Both of
>> these approaches were problematic, so this version
>> of the patch kit simply builds as a test case within the
>> plugin.exp suites.
>
> This is the part I'm least certain about, for two reasons:
>   * They are more like source files than tests, and I think I'd prefer
>     to have them alongside the source, in gcc/ rather than in the
>     testsuite. This way people are invariable going to fail to notice
>     them when they grep for something.
Excellent point.  I think this is worth some serious thought.  Given the 
state of GCC's sources, tests of this nature are going to be inherently 
tied to implementation details/sources rather than interfaces.  That's 
obviously not ideal, but it is where we are.  Combined with the 
cleanups/refactoring I think we ought to be doing, we've got a fairly 
strong argument to set these along side the sources.

The counter is that when grepping, you should probably be using 
find/xargs grep :-)



>   * This uses a plugin into whatever compiler was built, but sometimes
>     you can't really set up unit tests that way because what you want
>     to test depends on target specifics. What I've often wanted is a
>     special test target that gets built with a special machine
>     description that has whatever patterns are needed to replicate
>     tricky situations in reload or other optimization passes.
>
> The tests you have so far are focused mostly on high-level gimple/tree
> tests where this limitation is probably not showing up very much, but I
> think it would be better to have something that allows us to have more
> in-depth tests.
Yes.  But I think this level of testing is on another point in the 
testing continuum and will probably require some significant work beyond 
the unit testing being proposed by David.

jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/16] Unit tests framework (v3)
  2015-10-29 16:20               ` David Malcolm
@ 2015-10-29 19:38                 ` Jeff Law
  2015-10-29 22:32                   ` Mike Stump
  0 siblings, 1 reply; 176+ messages in thread
From: Jeff Law @ 2015-10-29 19:38 UTC (permalink / raw)
  To: David Malcolm, Bernd Schmidt; +Cc: gcc-patches

On 10/29/2015 10:10 AM, David Malcolm wrote:
>
> There may be useful things in gtest for us that I'm not using yet.  For
> example, the support for death tests may be useful for testing that e.g.
> our checking macros kill the program sanely in the presence of malformed
> internal data.
Please check on this.  I want to build a set of tests around the 
SSA_NAME manager, and that would include setting up can't happen 
situations and seeing if they're properly diagnosed by the checking 
code.  So obviously I have an interest in how the framework handles this 
kind of scenario.


>
> I wanted to reuse the gtest code on the grounds that:
>
>    * the code exists
>
>    * it's maintained (https://github.com/google/googletest
>      shows the last commit was 10 days ago)
>
>    * it has documentation:
> https://github.com/google/googletest/blob/master/googletest/docs/Primer.md
> (there's much more that just that)
>
>    * it will be familiar to some people from other projects
>
>
> That said, if it's a blocker, I can attempt a minimal reimplementation
> of the subset of the API that I'm using.
I'd probably lean towards continuing to use gtest.  I don't currently 
see a compelling reason to build another framework.

>
>>> v1 of the kit was structured as a frontend, v2 of the kit as
>>> a plugin that was built as if it were a frontend.  Both of
>>> these approaches were problematic, so this version
>>> of the patch kit simply builds as a test case within the
>>> plugin.exp suites.
>>
>> This is the part I'm least certain about, for two reasons:
>>    * They are more like source files than tests, and I think I'd prefer
>>      to have them alongside the source, in gcc/ rather than in the
>>      testsuite. This way people are invariable going to fail to notice
>>      them when they grep for something.
>
> So something like:
>
>    gcc/test-vec.c
>
> or even:
>
>    gcc/vec-tests.c
>
> so that it sorts next to gcc/vec.h in a listing?
>
> i.e.   gcc/FOO-tests.c  for gcc/FOO.c
>
> Maybe the unittests-plugin.c should live within the "gcc" directory?
It's a bit of bike-shedding :-)  I'd be happy with gcc/test-whatever or 
gcc/whatever-test.  Both have pluses/minuses and in the end I doubt it'd 
matter much.

My only worry here is doubling the number of files in gcc/.  But I'd 
claim that we want to have more subdirectories for major logical areas. 
  gimple/ rtl/ whatever, which would significantly mitigate the problem 
of too many files in gcc/


>
>>    * This uses a plugin into whatever compiler was built, but sometimes
>>      you can't really set up unit tests that way because what you want
>>      to test depends on target specifics. What I've often wanted is a
>>      special test target that gets built with a special machine
>>      description that has whatever patterns are needed to replicate
>>      tricky situations in reload or other optimization passes.
>>
>> The tests you have so far are focused mostly on high-level gimple/tree
>> tests where this limitation is probably not showing up very much, but I
>> think it would be better to have something that allows us to have more
>> in-depth tests.
>
> I think our long-term goal should be at least 5 styles of test:
>
> (A) end-to-end tests of the compiler: running it on some source and
> verifying properties of the diagnostics and/or generated code
> (potentially running it).  This is what we have today.
>
> (B) unit tests of individual subsystems: tests that exercise specific
> internal APIs e.g. containers like vec<>, hash_map<> etc, also things
> like gengtype.  This is a gap in our current test coverage, and what
> this patch kit aims to start filling.
Right.  It's essentially data structure and other very low level testing 
(gengtype).

That's even true if I think about the SSA_NAME manager -- in an ideal 
world, it'd just be a container for objects that we want to release & 
recycle, whether they're SSA_NAMEs, pseudos, whatever we decide has the 
right properties to benefit from recycling.  The fact that it's 
recycling SSA_NAMEs isn't for the most part all that important.



>
> (C) and (D): tests of specific passes: tests that accept IR (either
> gimple or RTL), and run just one pass, and verify properties of the IR
> emitted by the pass, or messages emitted by the pass.  LLVM has a "-R"
> remark option, so that a pass can issue remarks about what it's doing (a
> new kind of diagnostic):
>
> http://llvm.org/releases/3.5.0/tools/clang/docs/UsersManual.html#opt-rpass
>
> We could implement this kind of testing by implementing gimple and RTL
> frontends, and a -R option, which could integrate nicely with DejaGnu,
> with
>    /* { dg-remark "inlined here" } */
> and the like.
>
> This would require finishing the gimple FE, and writing an RTL FE
> (independent goals).  Hopefully that would give us test coverage for
> dealing with e.g. tricky reload situations.
Insert note from Richi (was it?) where he wants the gimple FE made real 
and integrated.  I think you'll have technical support if you want to 
tackle that next year.

Something similar for RTL would be cool, but probably even harder given 
the amount of state that's traditionally been kept out of the IL stream. 
  I'm sure some things are better today than in the past, but it's 
probably a very tanged mess to get to where we want to go with RTL.

jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 03/16] Add test-bitmap.c to unittests
  2015-10-27 19:31             ` [PATCH 03/16] Add test-bitmap.c " David Malcolm
@ 2015-10-29 21:36               ` Jeff Law
  0 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-10-29 21:36 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/27/2015 01:49 PM, David Malcolm wrote:
> gcc/testsuite/ChangeLog:
> 	* unittests/test-bitmap.c: New file.
OK if/when prereqs are approved.  Minor twiddling if we end up moving it 
elsewhere or standardizing/reducing header files is pre-approved.

jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 04/16] Add test-cfg.c to unittests
  2015-10-27 19:32             ` [PATCH 04/16] Add test-cfg.c to unittests David Malcolm
@ 2015-10-29 22:23               ` Jeff Law
  0 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-10-29 22:23 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/27/2015 01:49 PM, David Malcolm wrote:
> gcc/testsuite/ChangeLog:
> 	* unittests/test-cfg.c: New file.
> ---
>   gcc/testsuite/unittests/test-cfg.c | 319 +++++++++++++++++++++++++++++++++++++
>   1 file changed, 319 insertions(+)
>   create mode 100644 gcc/testsuite/unittests/test-cfg.c
>
> diff --git a/gcc/testsuite/unittests/test-cfg.c b/gcc/testsuite/unittests/test-cfg.c
>
> +/* These tests directly create CFGs.
> +   Compare with the static fns within tree-cfg.c:
> +     - build_gimple_cfg
> +     - make_blocks: calls create_basic_block (seq, bb);
> +     - make_edges.   */
> +
> +/* Verify a simple cfg of the form:
> +     ENTRY -> A -> B -> C -> EXIT.  */
> +TEST_F (cfg_test, linear_chain)
> +{
> +  gimple_register_cfg_hooks ();
> +
> +  tree fndecl = push_fndecl ("cfg_test_linear_chain");
> +  function *fun = DECL_STRUCT_FUNCTION (fndecl);
> +  EXPECT_TRUE (fun != NULL);
> +
> +  EXPECT_EQ (2, n_basic_blocks_for_fn (fun));
> +  EXPECT_EQ (0, n_edges_for_fn (fun));
Aren't those 3 redundant with the tests done by push_fndecl?


>
> +
> +/* Verify a simple CFG of the form:
> +     ENTRY
> +       |
> +       A
> +      / \
> +     /t  \f
> +    B     C
> +     \   /
> +      \ /
> +       D
> +       |
> +      EXIT.  */
> +TEST_F (cfg_test, diamond)
> +{
> +  gimple_register_cfg_hooks ();
> +
> +  tree fndecl = push_fndecl ("cfg_test_diamond");
> +  function *fun = DECL_STRUCT_FUNCTION (fndecl);
> +  EXPECT_TRUE (fun != NULL);
> +
> +  EXPECT_EQ (2, n_basic_blocks_for_fn (fun));
> +  EXPECT_EQ (0, n_edges_for_fn (fun));
Similarly here.


> +}  /* anon namespace.  */
> +
> +/* TODO: test the dominator/postdominator logic with various graphs/nodes:
> +   - loop
> +   - nested loops
> +   - switch statement (a block with many out-edges)
> +   - something that jumps to itself
> +   - etc  */
> +
> +/* TODO: add tests for loop-detection here?  */
I wonder what would happen if you called any of the internal cfg 
verification routines?!?

/me ducks.


Unless there's a good reason, drop the presumably redundant tests and 
this is OK.  Save preapprovald for these changes as the bitmap patch.

jeff


^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/16] Unit tests framework (v3)
  2015-10-29 19:38                 ` Jeff Law
@ 2015-10-29 22:32                   ` Mike Stump
  2015-10-30  3:59                     ` Jeff Law
  0 siblings, 1 reply; 176+ messages in thread
From: Mike Stump @ 2015-10-29 22:32 UTC (permalink / raw)
  To: Jeff Law; +Cc: David Malcolm, Bernd Schmidt, gcc-patches

On Oct 29, 2015, at 12:32 PM, Jeff Law <law@redhat.com> wrote:
> Something similar for RTL would be cool, but probably even harder given the amount of state that's traditionally been kept out of the IL stream.  I'm sure some things are better today than in the past, but it's probably a very tanged mess to get to where we want to go with RTL.

I had a bit of an rtl front end once.  It was never complete, and likely was the 20% effort that did 20% of the actual job that needs doing even for a simple hello world program.  Ah, too bad you didn’t ask around 10-15 years ago.  I likely could have just pull that code out of a bag, as it is, likely lost in time.

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/16] Unit tests framework (v3)
  2015-10-29 22:32                   ` Mike Stump
@ 2015-10-30  3:59                     ` Jeff Law
  0 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-10-30  3:59 UTC (permalink / raw)
  To: Mike Stump; +Cc: David Malcolm, Bernd Schmidt, gcc-patches

On 10/29/2015 04:22 PM, Mike Stump wrote:
> On Oct 29, 2015, at 12:32 PM, Jeff Law <law@redhat.com> wrote:
>> Something similar for RTL would be cool, but probably even harder
>> given the amount of state that's traditionally been kept out of the
>> IL stream.  I'm sure some things are better today than in the past,
>> but it's probably a very tanged mess to get to where we want to go
>> with RTL.
>
> I had a bit of an rtl front end once.  It was never complete, and
> likely was the 20% effort that did 20% of the actual job that needs
> doing even for a simple hello world program.  Ah, too bad you didnÂ’t
> ask around 10-15 years ago.  I likely could have just pull that code
> out of a bag, as it is, likely lost in time.
Back then an official RTL front-end would have been strictly verboten.

jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 05/16] Add test-et-forest.c to unittests
  2015-10-27 19:31             ` [PATCH 05/16] Add test-et-forest.c " David Malcolm
@ 2015-10-30  4:11               ` Jeff Law
  0 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-10-30  4:11 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/27/2015 01:49 PM, David Malcolm wrote:
> gcc/testsuite/ChangeLog:
> 	* unittests/test-et-forest.c: New file.

OK if/when prereqs are approved.  Minor twiddling if we end up moving it 
elsewhere or standardizing/reducing header files is pre-approved.

Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 11/16] Add test-hash-set.c to unittests
  2015-10-27 19:31             ` [PATCH 11/16] Add test-hash-set.c to unittests David Malcolm
@ 2015-10-30  4:54               ` Jeff Law
  0 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-10-30  4:54 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/27/2015 01:49 PM, David Malcolm wrote:
> gcc/testsuite/ChangeLog:
> 	* unittests/test-hash-set.c: New file.
OK if/when prereqs are approved.  Minor twiddling if we end up moving it 
elsewhere or standardizing/reducing header files is pre-approved.

Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 10/16] Add test-hash-map.c to unittests
  2015-10-27 19:32             ` [PATCH 10/16] Add test-hash-map.c " David Malcolm
@ 2015-10-30  4:57               ` Jeff Law
  0 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-10-30  4:57 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/27/2015 01:49 PM, David Malcolm wrote:
> gcc/testsuite/ChangeLog:
> 	* unittests/test-hash-map.c: New file.
OK if/when prereqs are approved.  Minor twiddling if we end up moving it 
elsewhere or standardizing/reducing header files is pre-approved.

Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 13/16] Add test-rtl.c to unittests
  2015-10-27 19:50             ` [PATCH 13/16] Add test-rtl.c " David Malcolm
@ 2015-10-30  4:58               ` Jeff Law
  2015-10-31 20:36                 ` Segher Boessenkool
  0 siblings, 1 reply; 176+ messages in thread
From: Jeff Law @ 2015-10-30  4:58 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/27/2015 01:49 PM, David Malcolm wrote:
> gcc/testsuite/ChangeLog:
> 	* unittests/test-rtl.c: New file.
> ---
>   gcc/testsuite/unittests/test-rtl.c | 94 ++++++++++++++++++++++++++++++++++++++
>   1 file changed, 94 insertions(+)
>   create mode 100644 gcc/testsuite/unittests/test-rtl.c
>
> diff --git a/gcc/testsuite/unittests/test-rtl.c b/gcc/testsuite/unittests/test-rtl.c
> new file mode 100644
> index 0000000..69eb444
> --- /dev/null
> +++ b/gcc/testsuite/unittests/test-rtl.c
> @@ -0,0 +1,94 @@
> +/* Unit tests for RTL-handling.
> +   Copyright (C) 2015 Free Software Foundation, Inc.
> +
> +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 "config.h"
> +#include "gtest/gtest.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "tm.h"
> +#include "opts.h"
> +#include "signop.h"
> +#include "hash-set.h"
> +#include "fixed-value.h"
> +#include "alias.h"
> +#include "flags.h"
> +#include "symtab.h"
> +#include "tree-core.h"
> +#include "stor-layout.h"
> +#include "tree.h"
> +#include "stringpool.h"
> +#include "stor-layout.h"
> +#include "rtl.h"
> +#include "pretty-print.h"
> +#include "cfgbuild.h"
> +#include "print-rtl.h"
> +
> +namespace {
> +
> +class rtl_test : public ::testing::Test
> +{
> + protected:
> +  void
> +  verify_print_pattern (const char *expected, rtx pat)
> +  {
> +    pretty_printer pp;
> +    print_pattern (&pp, pat, 1);
> +    EXPECT_STREQ (expected, pp_formatted_text (&pp));
> +  }
> +};
> +
> +/* Unit testing of "single_set".  */
> +TEST_F (rtl_test, test_single_set)
> +{
> +  /* A label is not a SET.  */
> +  EXPECT_EQ (NULL_RTX, single_set (gen_label_rtx ()));
> +
> +  /* An unconditional jump insn is a single SET.  */
> +  rtx set_pc = gen_rtx_SET (pc_rtx,
> +			    gen_rtx_LABEL_REF (VOIDmode,
> +					       gen_label_rtx ()));
> +  rtx_insn *jump_insn = emit_jump_insn (set_pc);
> +  EXPECT_EQ (set_pc, single_set (jump_insn));
> +
> +  /* etc */
> +}
Oh the things we could do here.  A parallel of multiple sets where all 
but one is unused is a single set, I can't recall if a single set in 
parallel with a jump/cond jump is a single set or not.  But the 
possibilities are sigificant.


> +
> +TEST_F (rtl_test, uncond_jump)
> +{
> +  rtx_insn *label = gen_label_rtx ();
> +  rtx jump_pat = gen_rtx_SET (pc_rtx,
> +			      gen_rtx_LABEL_REF (VOIDmode,
> +						 label));
> +  EXPECT_EQ (SET, jump_pat->code);
> +  EXPECT_EQ (LABEL_REF, SET_SRC (jump_pat)->code);
> +  EXPECT_EQ (label, LABEL_REF_LABEL (SET_SRC (jump_pat)));
> +  EXPECT_EQ (PC, SET_DEST (jump_pat)->code);
> +
> +  verify_print_pattern ("pc=L0", jump_pat);
> +
> +  rtx_insn *jump_insn = emit_jump_insn (jump_pat);
> +  EXPECT_FALSE (any_condjump_p (jump_insn));
> +  EXPECT_TRUE (any_uncondjump_p (jump_insn));
> +  EXPECT_TRUE (pc_set (jump_insn));
> +  EXPECT_TRUE (simplejump_p (jump_insn));
> +  EXPECT_TRUE (onlyjump_p (jump_insn));
> +  EXPECT_TRUE (control_flow_insn_p (jump_insn));
Similarly there's lots we could do here.

Anyway, I think at this stage we should think of this file as starting 
points/examples.

OK if/when prereqs are approved.  Minor twiddling if we end up moving it 
elsewhere or standardizing/reducing header files is pre-approved.


Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 14/16] Add test-tree.c to unittests
  2015-10-27 19:48             ` [PATCH 14/16] Add test-tree.c " David Malcolm
@ 2015-10-30  5:00               ` Jeff Law
  0 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-10-30  5:00 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/27/2015 01:49 PM, David Malcolm wrote:
> gcc/testsuite/ChangeLog:
> 	* unittests/test-tree.c: New file.
Same general comments as the RTL tests.

OK if/when prereqs are approved.  Minor twiddling if we end up moving it 
elsewhere or standardizing/reducing header files is pre-approved.

Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 09/16] Add test-gimple.c to unittests
  2015-10-27 19:58             ` [PATCH 09/16] Add test-gimple.c " David Malcolm
  2015-10-28 12:39               ` Richard Biener
@ 2015-10-30  5:02               ` Jeff Law
  1 sibling, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-10-30  5:02 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/27/2015 01:49 PM, David Malcolm wrote:
> gcc/testsuite/ChangeLog:
> 	* unittests/test-gimple.c: New file.
> ---
>   gcc/testsuite/unittests/test-gimple.c | 178 ++++++++++++++++++++++++++++++++++
>   1 file changed, 178 insertions(+)
>   create mode 100644 gcc/testsuite/unittests/test-gimple.c
>

> +
> +TEST_F (gimple_test, assign_binop)
> +{
> +  /* Build "tmp = a + b;"  */
Comment indicates addition.  But code actually generates a MULT_EXPR. 
Please fix.

OK if/when prereqs are approved.  Minor twiddling if we end up moving it 
elsewhere or standardizing/reducing header files is pre-approved.

Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 06/16] Add test-folding.c to unittests
  2015-10-27 19:35             ` [PATCH 06/16] Add test-folding.c " David Malcolm
@ 2015-10-30  5:06               ` Jeff Law
  0 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-10-30  5:06 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/27/2015 01:49 PM, David Malcolm wrote:
> gcc/testsuite/ChangeLog:
> 	* unittests/test-folding.c: New file.
OK if/when prereqs are approved.  Minor twiddling if we end up moving it 
elsewhere or standardizing/reducing header files is pre-approved.

Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 08/16] Add test-ggc.c to unittests
  2015-10-27 19:49             ` [PATCH 08/16] Add test-ggc.c " David Malcolm
@ 2015-10-30  5:08               ` Jeff Law
  0 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-10-30  5:08 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/27/2015 01:49 PM, David Malcolm wrote:
> gcc/testsuite/ChangeLog:
> 	* unittests/test-ggc.c: New file.
Not terribly happy with that counter to used to create a big list to 
detect recursion.  But I'm not offhand sure how to avoid without 
exposing more of the ggc system that is wise.

OK if/when prereqs are approved.  Minor twiddling if we end up moving it 
elsewhere or standardizing/reducing header files is pre-approved.


Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 12/16] Add test-locations.c to unittests
  2015-10-27 19:49             ` [PATCH 12/16] Add test-locations.c " David Malcolm
@ 2015-10-30  5:09               ` Jeff Law
  0 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-10-30  5:09 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/27/2015 01:49 PM, David Malcolm wrote:
> gcc/testsuite/ChangeLog:
> 	* unittests/test-locations.c: New file.
OK if/when prereqs are approved.  Minor twiddling if we end up moving it 
elsewhere or standardizing/reducing header files is pre-approved.

Consider removing the stuff we aren't actually using.  I think there was 
something simliar in another unittest file I looked at.

Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 15/16] Add test-vec.c to unittests
  2015-10-27 19:31             ` [PATCH 15/16] Add test-vec.c " David Malcolm
@ 2015-10-30  5:10               ` Jeff Law
  0 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-10-30  5:10 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/27/2015 01:49 PM, David Malcolm wrote:
> gcc/testsuite/ChangeLog:
> 	* unittests/test-vec.c: New file.
OK if/when prereqs are approved.  Minor twiddling if we end up moving it 
elsewhere or standardizing/reducing header files is pre-approved.

Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 16/16] Add test-wide-int.c to unittests
  2015-10-27 19:51             ` [PATCH 16/16] Add test-wide-int.c " David Malcolm
@ 2015-10-30  5:15               ` Jeff Law
  0 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-10-30  5:15 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/27/2015 01:49 PM, David Malcolm wrote:
> gcc/testsuite/ChangeLog:
> 	* unittests/test-wide-int.c: New file.
OK if/when prereqs are approved.  Minor twiddling if we end up moving it 
elsewhere or standardizing/reducing header files is pre-approved.

Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 07/16] Add test-functions.c to unittests
  2015-10-27 19:32             ` [PATCH 07/16] Add test-functions.c " David Malcolm
@ 2015-10-30  5:19               ` Jeff Law
  0 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-10-30  5:19 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/27/2015 01:49 PM, David Malcolm wrote:
> gcc/testsuite/ChangeLog:
> 	* unittests/test-functions.c: New file.
There's some if (0) code in here that needs to be eliminated.

The RTL case in particular is probably stretching the limits of what we 
can do with the framework right now.  Or more correctly what folks are 
likely to write within this framework.

We may need to build up a library of bits that do common things so that 
we're not repeating that stuff all over the place.

As far as RTL testing, as you note, once we hit RTL we're going to have 
far more target dependencies to contend with.  Testing will be nontrivial.

OK if/when prereqs are approved.  Minor twiddling if we end up moving it 
elsewhere or standardizing/reducing header files is pre-approved.

Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 01/16] Add unittest infrastructure
  2015-10-27 19:31             ` [PATCH 01/16] Add unittest infrastructure David Malcolm
@ 2015-10-30  5:20               ` Jeff Law
  0 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-10-30  5:20 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/27/2015 01:49 PM, David Malcolm wrote:
> gcc/testsuite/ChangeLog:
> 	* g++.dg/plugin/plugin.exp (plugin_test_list): Add the unittests
> 	plugin.
> 	* g++.dg/plugin/unittests.C: New file.
> 	* gcc.dg/plugin/plugin.exp (plugin_test_list): Add the unittests
> 	plugin.
> 	* gcc.dg/plugin/unittests.c: New file.
> 	* lib/plugin-support.exp (dg-plugin-run-gengtype): New function.
> 	(plugin-get-options): Handle dg-plugin-run-gengtype.
> 	* lib/prune.exp (prune_gcc_output): Process any DejaGnu output
> 	from the test, and convert into results at this level, prefixing
> 	with the testcase.
> 	* unittests/unittests-plugin.c: New file.
I've noted the concerns WRT hooking into the pruning code.  I won't 
repeat them.

There's a fair amount of if 0, #if 0 code in here that needs cleaning up.

And we've got the meta question, should these tests live somewhere 
different.

So I don't see anything else that would cause me to reject this -- but 
I'm going hold off on final approval pending discussion on where the 
tests will live as that may have an impact on this infrastructure.

jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/16] Unit tests framework (v3)
  2015-10-27 20:16             ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
@ 2015-10-30  5:28               ` Jeff Law
  0 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-10-30  5:28 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/27/2015 01:58 PM, David Malcolm wrote:
> On Tue, 2015-10-27 at 15:48 -0400, David Malcolm wrote:
> [...snip...]
>
> Looks like [Patch 02/16] was too big (1.2MB) for the list;
> it can be seen here:
> https://dmalcolm.fedorapeople.org/gcc/2015-10-27/unittests/0002-Add-embedded-copy-of-gtest-1.7-to-unittests.patch
DO we really need to embed a copy of gtest?  Can we just make it a prereq?

Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/16] Unit tests framework (v3)
  2015-10-29 19:21               ` Jeff Law
@ 2015-10-30 10:54                 ` Bernd Schmidt
  2015-10-30 16:08                   ` Jeff Law
  0 siblings, 1 reply; 176+ messages in thread
From: Bernd Schmidt @ 2015-10-30 10:54 UTC (permalink / raw)
  To: Jeff Law, David Malcolm, gcc-patches

On 10/29/2015 08:21 PM, Jeff Law wrote:
> Excellent point.  I think this is worth some serious thought.  Given the
> state of GCC's sources, tests of this nature are going to be inherently
> tied to implementation details/sources rather than interfaces.  That's
> obviously not ideal, but it is where we are.  Combined with the
> cleanups/refactoring I think we ought to be doing, we've got a fairly
> strong argument to set these along side the sources.
>
> The counter is that when grepping, you should probably be using
> find/xargs grep :-)

There's actually a tool called ack which automates that. But we've often 
seen cases where people fail to spot occurrences in config/ directories. 
I think tests for things like bitmap or wide-int could well live at the 
end of the respective source files - this would be the most convenient 
location so that if you add a new bitmap function, you can immediately 
add tests as well.

Do we even support plugins on every host?

>> The tests you have so far are focused mostly on high-level gimple/tree
>> tests where this limitation is probably not showing up very much, but I
>> think it would be better to have something that allows us to have more
>> in-depth tests.
> Yes.  But I think this level of testing is on another point in the
> testing continuum and will probably require some significant work beyond
> the unit testing being proposed by David.

Not sure about significant - it shouldn't take long to set up an extra 
test-gcc build at the top-level if we decide to go with that and add a 
-ftest option. I think it's worth spending some time thinking long-term 
about what the best way to go about this would be.


Bernd

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/16] Unit tests framework (v3)
  2015-10-30 10:54                 ` Bernd Schmidt
@ 2015-10-30 16:08                   ` Jeff Law
  2015-11-16 18:17                     ` Bernd Schmidt
  0 siblings, 1 reply; 176+ messages in thread
From: Jeff Law @ 2015-10-30 16:08 UTC (permalink / raw)
  To: Bernd Schmidt, David Malcolm, gcc-patches

On 10/30/2015 04:54 AM, Bernd Schmidt wrote:
>> The counter is that when grepping, you should probably be using
>> find/xargs grep :-)
>
> There's actually a tool called ack which automates that. But we've often
> seen cases where people fail to spot occurrences in config/ directories.
We certainly have.  Never saw "ack" before, I wonder if I can retrain 
myself to use it over find/grep :-)  And it does seem damn fast.

> I think tests for things like bitmap or wide-int could well live at the
> end of the respective source files - this would be the most convenient
> location so that if you add a new bitmap function, you can immediately
> add tests as well.
It has benefits as you noted above.  What I don't like is the ifdefs 
we'll need to ensure the testing bits don't bloat cc1 and friends.

I can live with any of the 3 proposals (in testsuite directory, 
alongside sources, inside existing sources) with the explicit assumption 
that if we try one and it does't work out that we might experiment with 
another.  In my mind we're very early in this process, so course 
corrections may be necessary.


>
> Do we even support plugins on every host?
I would think not :-)

>
>>> The tests you have so far are focused mostly on high-level gimple/tree
>>> tests where this limitation is probably not showing up very much, but I
>>> think it would be better to have something that allows us to have more
>>> in-depth tests.
>> Yes.  But I think this level of testing is on another point in the
>> testing continuum and will probably require some significant work beyond
>> the unit testing being proposed by David.
>
> Not sure about significant - it shouldn't take long to set up an extra
> test-gcc build at the top-level if we decide to go with that and add a
> -ftest option. I think it's worth spending some time thinking long-term
> about what the best way to go about this would be.
If we look at the cfg tests you'll see one that we take down to 
generation of RTL.  But the pain in setting that up is significant IMHO. 
  Enough that I doubt many folks are willing to go to those lengths to 
write RTL (or even most gimple) tests.

The first high level question is how do we envision writing those tests. 
  I don't think the style shown in the gimple test is sustainable long 
term.  We've got to get past hand creating cfgs, cfun, basic rtl and 
tree nodes, etc etc.  Which argues that true gimple & rtl testing ought 
to be sucking in gimple/rtl to start (ie, gimple & rtl front-ends).  So 
until those are in place, I just don't see going very far with testing 
at a level much higher than David's doing right now.

The other way would be to look at the pain of setting up all the 
required state and say it's a failing in the APIs of GCC itself and that 
if we had the right APIs in place, constructing enough state to do this 
kind of testing would be relatively easy.

David has mentioned working on the gimple front-end as his next 
significant project.  I suspect we'll learn a ton from that work and 
wiring it into a test harness -- lessons I'd like to have under our belt 
prior to tacking the RTL testing side.  Similarly I suspect we'll learn 
a lot about weaknesses in our API interfaces trying to write tests at a 
level just above what David's targeting right now.

Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 13/16] Add test-rtl.c to unittests
  2015-10-30  4:58               ` Jeff Law
@ 2015-10-31 20:36                 ` Segher Boessenkool
  0 siblings, 0 replies; 176+ messages in thread
From: Segher Boessenkool @ 2015-10-31 20:36 UTC (permalink / raw)
  To: Jeff Law; +Cc: David Malcolm, gcc-patches

On Thu, Oct 29, 2015 at 10:57:53PM -0600, Jeff Law wrote:
> Oh the things we could do here.  A parallel of multiple sets where all 
> but one is unused is a single set, I can't recall if a single set in 
> parallel with a jump/cond jump is a single set or not.

It is not, it is two SETs (one of PC).


Segher

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/16] Unit tests framework (v3)
  2015-10-30 16:08                   ` Jeff Law
@ 2015-11-16 18:17                     ` Bernd Schmidt
  2015-11-16 18:48                       ` David Malcolm
  2015-11-19 16:46                       ` [PATCH 00/15] Unittests framework v4: -fself-test David Malcolm
  0 siblings, 2 replies; 176+ messages in thread
From: Bernd Schmidt @ 2015-11-16 18:17 UTC (permalink / raw)
  To: Jeff Law, David Malcolm, gcc-patches

So Jeff and I just had a chat, and we came up with some thoughts about 
how to proceed. I think we both agree that it would be good to have a 
special testing backend, along with frontends designed to be able to 
read in gimple or rtl that can be operated on. That's more of a 
long-term thing.

For some of the simpler infrastructure tests such as the ones in this 
patch kit (bitmap, vec or wide-int functionality testing and such), we 
had the idea of putting these into every ENABLE_CHECKING compiler, and 
run them after building stage1, controlled by a -fself-test flag. It's 
better to detect such basic failures early rather than complete a full 
bootstrap and test cycle. It also keeps the tests alongside the rest of 
the implementation, which I consider desirable for such relatively 
simple data structures.

Thoughts?


Bernd

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/16] Unit tests framework (v3)
  2015-11-16 18:17                     ` Bernd Schmidt
@ 2015-11-16 18:48                       ` David Malcolm
  2015-11-16 21:22                         ` Bernd Schmidt
  2015-11-16 23:12                         ` Jeff Law
  2015-11-19 16:46                       ` [PATCH 00/15] Unittests framework v4: -fself-test David Malcolm
  1 sibling, 2 replies; 176+ messages in thread
From: David Malcolm @ 2015-11-16 18:48 UTC (permalink / raw)
  To: Bernd Schmidt; +Cc: Jeff Law, gcc-patches

On Mon, 2015-11-16 at 19:17 +0100, Bernd Schmidt wrote:
> So Jeff and I just had a chat, and we came up with some thoughts about 
> how to proceed. I think we both agree that it would be good to have a 
> special testing backend, along with frontends designed to be able to 
> read in gimple or rtl that can be operated on. That's more of a 
> long-term thing.

(nods)  FWIW, I'm interesting in trying to get the gimple FE into gcc 7.

> For some of the simpler infrastructure tests such as the ones in this 
> patch kit (bitmap, vec or wide-int functionality testing and such), we 
> had the idea of putting these into every ENABLE_CHECKING compiler, and 
> run them after building stage1, controlled by a -fself-test flag. It's 
> better to detect such basic failures early rather than complete a full 
> bootstrap and test cycle. It also keeps the tests alongside the rest of 
> the implementation, which I consider desirable for such relatively 
> simple data structures.

Would it be reasonable to run them at each stage?  My hope is that they
will be fast.

If we're building the tests into the compiler itself, guarded by
  #if ENABLE_CHECKING
then presumably it makes sense to put the tests directly into the
pertinent source files? (rather than in a "foo-tests.c" file).  Possibly
even to interleave them, to be next to the code in question.

Given that this patch kit has seen a fair amount of discussion, and
parts of it are already approved, and that it's designed to improve our
test coverage, is it reasonable to continue pursuing this within stage
3?  (I hope so)  Should I attempt a patch for the above? (once I've
fixed the AIX bootstrap issue, of course)

Any thoughts on embedded gtest vs external gtest vs building our own?
If we're embedding, it may make most sense to build our own minimal
implementation, with a similar API (to avoid relying on the C++ stdlib,
which gtest does; that was the most awkward part of dealing with it,
iirc); this would be simpler, I suspect.


Dave


^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/16] Unit tests framework (v3)
  2015-11-16 18:48                       ` David Malcolm
@ 2015-11-16 21:22                         ` Bernd Schmidt
  2015-11-16 23:12                         ` Jeff Law
  1 sibling, 0 replies; 176+ messages in thread
From: Bernd Schmidt @ 2015-11-16 21:22 UTC (permalink / raw)
  To: David Malcolm; +Cc: Jeff Law, gcc-patches


>> For some of the simpler infrastructure tests such as the ones in this
>> patch kit (bitmap, vec or wide-int functionality testing and such), we
>> had the idea of putting these into every ENABLE_CHECKING compiler, and
>> run them after building stage1, controlled by a -fself-test flag. It's
>> better to detect such basic failures early rather than complete a full
>> bootstrap and test cycle. It also keeps the tests alongside the rest of
>> the implementation, which I consider desirable for such relatively
>> simple data structures.
>
> Would it be reasonable to run them at each stage?  My hope is that they
> will be fast.

Depends on how fast, I guess. I don't think testing them more than once 
gains very much; if there's a suspicion that stage3 was miscompiled one 
could still run -fself-test manually.

> If we're building the tests into the compiler itself, guarded by
>    #if ENABLE_CHECKING
> then presumably it makes sense to put the tests directly into the
> pertinent source files? (rather than in a "foo-tests.c" file).  Possibly
> even to interleave them, to be next to the code in question.

Yes, I was thinking same source file for the most part. I don't think 
there has to be any kind of rule, we just do whatever makes sense.

> Given that this patch kit has seen a fair amount of discussion, and
> parts of it are already approved, and that it's designed to improve our
> test coverage, is it reasonable to continue pursuing this within stage
> 3?  (I hope so)  Should I attempt a patch for the above? (once I've
> fixed the AIX bootstrap issue, of course)

As far as I'm concerned this can still proceed given that it was 
submitted well in advance of stage 3 (unless someone objects).

> Any thoughts on embedded gtest vs external gtest vs building our own?

I think for -fself-test we can mostly operate with gcc_assert, IMO 
there's no need to use an elaborate framework. We can revisit this issue 
when we get to more extensive tests that require multiple compiler 
invocations.


Bernd

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/16] Unit tests framework (v3)
  2015-11-16 18:48                       ` David Malcolm
  2015-11-16 21:22                         ` Bernd Schmidt
@ 2015-11-16 23:12                         ` Jeff Law
  2015-11-17  1:54                           ` Mike Stump
  1 sibling, 1 reply; 176+ messages in thread
From: Jeff Law @ 2015-11-16 23:12 UTC (permalink / raw)
  To: David Malcolm, Bernd Schmidt; +Cc: gcc-patches

On 11/16/2015 11:48 AM, David Malcolm wrote:

>> For some of the simpler infrastructure tests such as the ones in this
>> patch kit (bitmap, vec or wide-int functionality testing and such), we
>> had the idea of putting these into every ENABLE_CHECKING compiler, and
>> run them after building stage1, controlled by a -fself-test flag. It's
>> better to detect such basic failures early rather than complete a full
>> bootstrap and test cycle. It also keeps the tests alongside the rest of
>> the implementation, which I consider desirable for such relatively
>> simple data structures.
>
> Would it be reasonable to run them at each stage?  My hope is that they
> will be fast.
But with what value?  The point here is basic testing coverage of things 
like low level data structures and such.  The odds that we break 
something in those that show up under unit testing during stage2/stage3, 
but not during stage1 or during the compiler itself would be small I 
would think.

>
> If we're building the tests into the compiler itself, guarded by
>    #if ENABLE_CHECKING
> then presumably it makes sense to put the tests directly into the
> pertinent source files? (rather than in a "foo-tests.c" file).  Possibly
> even to interleave them, to be next to the code in question.
I'm of two minds.  I really don't like the idea of lots of #ifs mucking 
up the sources.  So I'd tend to want them either at the end of the file 
with a single #if CHECKING_P or as a separate foo-tests file.  We may 
want to get at static objects/functions from within a test (to either 
set or query state), so that would tend to argue that within the 
existing .c files.


> Given that this patch kit has seen a fair amount of discussion, and
> parts of it are already approved, and that it's designed to improve our
> test coverage, is it reasonable to continue pursuing this within stage
> 3?  (I hope so)  Should I attempt a patch for the above? (once I've
> fixed the AIX bootstrap issue, of course)
I'm leaning towards suggesting we get on a branch and look to merge it 
into the next stage1.  This isn't something that's going to have a user 
impact.

>
> Any thoughts on embedded gtest vs external gtest vs building our own?
> If we're embedding, it may make most sense to build our own minimal
> implementation, with a similar API (to avoid relying on the C++ stdlib,
> which gtest does; that was the most awkward part of dealing with it,
> iirc); this would be simpler, I suspect.
I'd lean towards external gtest.  I realize it's another dependency, but 
it's a testing only dependency, so it's not any worse in my mind than 
dejagnu.

jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/16] Unit tests framework (v3)
  2015-11-16 23:12                         ` Jeff Law
@ 2015-11-17  1:54                           ` Mike Stump
  2015-11-17 12:51                             ` Bernd Schmidt
  0 siblings, 1 reply; 176+ messages in thread
From: Mike Stump @ 2015-11-17  1:54 UTC (permalink / raw)
  To: Jeff Law; +Cc: David Malcolm, Bernd Schmidt, gcc-patches

On Nov 16, 2015, at 3:12 PM, Jeff Law <law@redhat.com> wrote:
> So I'd tend to want them either at the end of the file with a single #if CHECKING_P or as a separate foo-tests file.

Hum…  I kinda don’t want the main files mucked up with tests.  I think I’d rather have

#if CHECKING_P
#include "test/expr-test.h"
#endif

at the end, and punt the whole lot into a single subdirectory that most people, most of the time, can simply ignore.  Wading through a ton of code that you aren’t interested in, is, well, annoying.  We so rarely change apis that I don’t see the harm in the separation.  Since we default to testing, and since the test suite will horrifically fail (if it works) if people do it wrong, I don’t think people will forget to update the test suite as the apis change.

> I'm leaning towards suggesting we get on a branch and look to merge it into the next stage1.  This isn't something that's going to have a user impact.

Depends on the patch set, but, I’d like to think most would be fairly safe to put in post stage 1.

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/16] Unit tests framework (v3)
  2015-11-17  1:54                           ` Mike Stump
@ 2015-11-17 12:51                             ` Bernd Schmidt
  2015-11-17 18:06                               ` Jeff Law
  0 siblings, 1 reply; 176+ messages in thread
From: Bernd Schmidt @ 2015-11-17 12:51 UTC (permalink / raw)
  To: Mike Stump, Jeff Law; +Cc: David Malcolm, gcc-patches

On 11/17/2015 02:53 AM, Mike Stump wrote:
> On Nov 16, 2015, at 3:12 PM, Jeff Law <law@redhat.com> wrote:
>> So I'd tend to want them either at the end of the file with a
>> single #if CHECKING_P or as a separate foo-tests file.
>
> HumÂ…  I kinda donÂ’t want the main files mucked up with tests.  I
> think IÂ’d rather have
>
> #if CHECKING_P #include "test/expr-test.h" #endif
>
> at the end, and punt the whole lot into a single subdirectory that
> most people, most of the time, can simply ignore.  Wading through a
> ton of code that you arenÂ’t interested in, is, well, annoying.

Most of the tests submitted so far are relatively tiny, sometimes the 
list of #includes in the testcase is longer than the tests themselves. 
If they are at the end of a file you'd hardly be wading through them 
either. Let's just use common sense and make separate files if we ever 
get huge amounts of test code and keep it simple otherwise.


Bernd

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/16] Unit tests framework (v3)
  2015-11-17 12:51                             ` Bernd Schmidt
@ 2015-11-17 18:06                               ` Jeff Law
  0 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-11-17 18:06 UTC (permalink / raw)
  To: Bernd Schmidt, Mike Stump; +Cc: David Malcolm, gcc-patches

On 11/17/2015 05:51 AM, Bernd Schmidt wrote:
> On 11/17/2015 02:53 AM, Mike Stump wrote:
>> On Nov 16, 2015, at 3:12 PM, Jeff Law <law@redhat.com> wrote:
>>> So I'd tend to want them either at the end of the file with a
>>> single #if CHECKING_P or as a separate foo-tests file.
>>
>> HumÂ…  I kinda donÂ’t want the main files mucked up with tests.  I
>> think IÂ’d rather have
>>
>> #if CHECKING_P #include "test/expr-test.h" #endif
>>
>> at the end, and punt the whole lot into a single subdirectory that
>> most people, most of the time, can simply ignore.  Wading through a
>> ton of code that you arenÂ’t interested in, is, well, annoying.
>
> Most of the tests submitted so far are relatively tiny, sometimes the
> list of #includes in the testcase is longer than the tests themselves.
> If they are at the end of a file you'd hardly be wading through them
> either. Let's just use common sense and make separate files if we ever
> get huge amounts of test code and keep it simple otherwise.
I'd been pondering a #include solution too.  But at this stage I don't 
think it buys us anything significant beyond just putting them at the 
end of the source files.  Obviously if we find that the tests are 
intrusive, then we can adjust.

One could legitimately ask what about tests that hit multiple source 
files.  The snarky response is that such tests aren't really suitable 
for unit testing :-)  But for those we can create a separate source 
file, or put them into the most logical location.

Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 00/15] Unittests framework v4: -fself-test
  2015-11-16 18:17                     ` Bernd Schmidt
  2015-11-16 18:48                       ` David Malcolm
@ 2015-11-19 16:46                       ` David Malcolm
  2015-11-19 16:46                         ` [PATCH 07/15] Fix warning in function-tests.c David Malcolm
                                           ` (15 more replies)
  1 sibling, 16 replies; 176+ messages in thread
From: David Malcolm @ 2015-11-19 16:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

On Mon, 2015-11-16 at 19:17 +0100, Bernd Schmidt wrote:
> So Jeff and I just had a chat, and we came up with some thoughts about 
> how to proceed. I think we both agree that it would be good to have a 
> special testing backend, along with frontends designed to be able to 
> read in gimple or rtl that can be operated on. That's more of a 
> long-term thing.
> 
> For some of the simpler infrastructure tests such as the ones in this 
> patch kit (bitmap, vec or wide-int functionality testing and such), we 
> had the idea of putting these into every ENABLE_CHECKING compiler, and 
> run them after building stage1, controlled by a -fself-test flag. It's 
> better to detect such basic failures early rather than complete a full 
> bootstrap and test cycle. It also keeps the tests alongside the rest of 
> the implementation, which I consider desirable for such relatively 
> simple data structures.
> 
> Thoughts?

I like the idea.

Here's another iteration of the patch kit, which implements it (mostly).

David Malcolm (15):
  Selftest framework (unittests v4)
  Add selftests to bitmap.c
  Add selftests to tree-cfg.c
  Add selftests to et-forest.c
  Add selftests to fold-const.c
  Add function-tests.c
  Fix warning in function-tests.c
  Add selftests to gimple.c
  Add hash-map-tests.c
  Add hash-set-tests.c
  Add selftests to input.c
  Add rtl-tests.c
  Add selftests to tree.c
  Add selftests to vec.c
  RFC: Add ggc-tests.c

 gcc/Makefile.in      |   9 +-
 gcc/bitmap.c         |  92 ++++++++
 gcc/common.opt       |   4 +
 gcc/et-forest.c      |  99 ++++++++
 gcc/fold-const.c     |  66 ++++++
 gcc/function-tests.c | 632 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/ggc-tests.c      | 302 ++++++++++++++++++++++++
 gcc/gimple.c         | 103 +++++++++
 gcc/hash-map-tests.c |  81 +++++++
 gcc/hash-set-tests.c |  57 +++++
 gcc/input.c          | 107 +++++++++
 gcc/rtl-tests.c      |  98 ++++++++
 gcc/selftest.c       | 152 +++++++++++++
 gcc/selftest.h       | 270 ++++++++++++++++++++++
 gcc/toplev.c         |  51 +++++
 gcc/toplev.h         |   2 +
 gcc/tree-cfg.c       | 264 +++++++++++++++++++++
 gcc/tree.c           |  47 ++++
 gcc/vec.c            | 142 ++++++++++++
 19 files changed, 2575 insertions(+), 3 deletions(-)
 create mode 100644 gcc/function-tests.c
 create mode 100644 gcc/ggc-tests.c
 create mode 100644 gcc/hash-map-tests.c
 create mode 100644 gcc/hash-set-tests.c
 create mode 100644 gcc/rtl-tests.c
 create mode 100644 gcc/selftest.c
 create mode 100644 gcc/selftest.h

-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 06/15] Add function-tests.c
  2015-11-19 16:46                       ` [PATCH 00/15] Unittests framework v4: -fself-test David Malcolm
                                           ` (6 preceding siblings ...)
  2015-11-19 16:46                         ` [PATCH 10/15] Add hash-set-tests.c David Malcolm
@ 2015-11-19 16:46                         ` David Malcolm
  2015-11-19 16:46                         ` [PATCH 13/15] Add selftests to tree.c David Malcolm
                                           ` (7 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-11-19 16:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-functions.c):
  https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03310.html
with:

> There's some if (0) code in here that needs to be eliminated.

(done)

> The RTL case in particular is probably stretching the limits of what
> we can do with the framework right now. Or more correctly what folks
> are likely to write within this framework.
>
> We may need to build up a library of bits that do common things so
> that we're not repeating that stuff all over the place.
>
> As far as RTL testing, as you note, once we hit RTL we're going to
> have far more target dependencies to contend with. Testing will
> be nontrivial.
>
> OK if/when prereqs are approved. Minor twiddling if we end up moving
> it elsewhere or standardizing/reducing header files is pre-approved.

Like other moves, this one gains #if CHECKING_P, and the change of
include from gtest/gtest.h to selftest.h.

gcc/ChangeLog:
	* function-tests.c: New file.
---
 gcc/function-tests.c | 630 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 630 insertions(+)
 create mode 100644 gcc/function-tests.c

diff --git a/gcc/function-tests.c b/gcc/function-tests.c
new file mode 100644
index 0000000..58b27b8
--- /dev/null
+++ b/gcc/function-tests.c
@@ -0,0 +1,630 @@
+/* Unit tests for function-handling.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "hard-reg-set.h"
+#include "input.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "gimple-expr.h"
+#include "toplev.h"
+#include "print-tree.h"
+#include "tree-iterator.h"
+#include "gimplify.h"
+#include "tree-cfg.h"
+#include "basic-block.h"
+#include "double-int.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "stmt.h"
+#include "hash-table.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "context.h"
+#include "hash-map.h"
+#include "plugin-api.h"
+#include "ipa-ref.h"
+#include "cgraph.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+namespace {
+
+class function_test : public ::selftest::test
+{
+ protected:
+  tree
+  make_fndecl (tree return_type,
+	       const char *name,
+	       vec <tree> &param_types,
+	       bool is_variadic = false)
+  {
+    tree fn_type;
+    if (is_variadic)
+      fn_type = build_varargs_function_type_array (return_type,
+						   param_types.length (),
+						   param_types.address ());
+    else
+      fn_type = build_function_type_array (return_type,
+					   param_types.length (),
+					   param_types.address ());
+    /* FIXME: this uses input_location: */
+    tree fndecl = build_fn_decl (name, fn_type);
+
+    return fndecl;
+  }
+};
+
+TEST_F (function_test, fndecl_int_void)
+{
+  auto_vec <tree> param_types;
+  tree fndecl = make_fndecl (integer_type_node,
+			     "test_fndecl_int_void",
+			     param_types);
+  ASSERT_TRUE (fndecl != NULL);
+
+  /* Verify name of decl.  */
+  tree declname = DECL_NAME (fndecl);
+  ASSERT_TRUE (declname != NULL);
+  EXPECT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
+  /* We expect it to use a *copy* of the string we passed in.  */
+  const char *identifier_ptr = IDENTIFIER_POINTER (declname);
+  EXPECT_NE ("test_fndecl_int_void", identifier_ptr);
+  EXPECT_EQ (0, strcmp ("test_fndecl_int_void", identifier_ptr));
+
+  /* Verify type of fndecl.  */
+  EXPECT_EQ (FUNCTION_DECL, TREE_CODE (fndecl));
+  tree fntype = TREE_TYPE (fndecl);
+  EXPECT_EQ (FUNCTION_TYPE, TREE_CODE (fntype));
+
+  /* Verify return type.  */
+  EXPECT_EQ (integer_type_node, TREE_TYPE (fntype));
+
+  /* Verify "void" args.  */
+  tree argtypes = TYPE_ARG_TYPES (fntype);
+  EXPECT_EQ (TREE_LIST, TREE_CODE (argtypes));
+  EXPECT_EQ (void_type_node, TREE_VALUE (argtypes));
+  EXPECT_EQ (NULL, TREE_CHAIN (argtypes));
+}
+
+TEST_F (function_test, fndecl_float_intchar)
+{
+  auto_vec <tree> param_types;
+  param_types.safe_push (integer_type_node);
+  param_types.safe_push (char_type_node);
+  tree fndecl = make_fndecl (float_type_node,
+			     "test_fndecl_float_intchar",
+			     param_types);
+  ASSERT_TRUE (fndecl != NULL);
+
+  /* Verify name of decl.  */
+  tree declname = DECL_NAME (fndecl);
+  ASSERT_TRUE (declname != NULL);
+  EXPECT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
+  /* We expect it to use a *copy* of the string we passed in.  */
+  const char *identifier_ptr = IDENTIFIER_POINTER (declname);
+  EXPECT_NE ("test_fndecl_float_intchar", identifier_ptr);
+  EXPECT_EQ (0, strcmp ("test_fndecl_float_intchar", identifier_ptr));
+
+  /* Verify type of fndecl.  */
+  EXPECT_EQ (FUNCTION_DECL, TREE_CODE (fndecl));
+  tree fntype = TREE_TYPE (fndecl);
+  EXPECT_EQ (FUNCTION_TYPE, TREE_CODE (fntype));
+
+  /* Verify return type.  */
+  EXPECT_EQ (float_type_node, TREE_TYPE (fntype));
+
+  /* Verify "(int, char)" args.  */
+  tree arg0 = TYPE_ARG_TYPES (fntype);
+  EXPECT_EQ (TREE_LIST, TREE_CODE (arg0));
+  EXPECT_EQ (integer_type_node, TREE_VALUE (arg0));
+  tree arg1 = TREE_CHAIN (arg0);
+  ASSERT_TRUE (arg1 != NULL);
+  EXPECT_EQ (TREE_LIST, TREE_CODE (arg1));
+  EXPECT_EQ (char_type_node, TREE_VALUE (arg1));
+  tree argterm = TREE_CHAIN (arg1);
+  ASSERT_TRUE (argterm != NULL);
+  EXPECT_EQ (TREE_LIST, TREE_CODE (argterm));
+  EXPECT_EQ (void_type_node, TREE_VALUE (argterm));
+  EXPECT_EQ (NULL, TREE_CHAIN (argterm));
+}
+
+/* The test cases using this fixture take a trivial function:
+
+     int test_fn (void) { return 42; }
+
+   and test various conversions done to it:
+
+   - gimplification
+   - construction of the CFG
+   - conversion to SSA form
+   - expansion to RTL form
+
+   In avoid having one overlong test case, this is broken
+   up into separate test cases for each stage, with helper methods
+   in this fixture to minimize code duplication.
+
+   Another approach would be to attempt to directly construct a function
+   in the appropriate representation at each stage, though presumably
+   that would exhibit different kinds of failure compared to this
+   approach.  */
+
+class representation_test : public function_test
+{
+ protected:
+  /* Construct this function:
+       int test_fn (void) { return 42; }
+     in generic tree form.  Return the fndecl.  */
+  tree
+  build_trivial_generic_function ()
+  {
+    auto_vec <tree> param_types;
+    tree fndecl = make_fndecl (integer_type_node,
+			       "test_fn",
+			       param_types);
+    EXPECT_TRUE (fndecl != NULL);
+
+    /* Populate the function.  */
+    tree retval = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+			      NULL_TREE, integer_type_node);
+    DECL_ARTIFICIAL (retval) = 1;
+    DECL_IGNORED_P (retval) = 1;
+    DECL_RESULT (fndecl) = retval;
+
+    /* Create a BIND_EXPR, and within it, a statement list.  */
+    tree stmt_list = alloc_stmt_list ();
+    tree_stmt_iterator stmt_iter = tsi_start (stmt_list);
+    tree block = make_node (BLOCK);
+    tree bind_expr =
+      build3 (BIND_EXPR, void_type_node, NULL, stmt_list, block);
+
+    tree modify_retval = build2 (MODIFY_EXPR,
+				 integer_type_node,
+				 retval,
+				 build_int_cst (integer_type_node, 42));
+    tree return_stmt = build1 (RETURN_EXPR,
+			       integer_type_node,
+			       modify_retval);
+    tsi_link_after (&stmt_iter, return_stmt, TSI_CONTINUE_LINKING);
+
+    DECL_INITIAL (fndecl) = block;
+
+    /* how to add to function? the following appears to be how to
+       set the body of a fndecl: */
+    DECL_SAVED_TREE(fndecl) = bind_expr;
+
+    /* Ensure that locals appear in the debuginfo.  */
+    BLOCK_VARS (block) = BIND_EXPR_VARS (bind_expr);
+
+    return fndecl;
+  }
+
+  /* Construct this function:
+       int test_fn (void) { return 42; }
+     in "high gimple" form.  Return the fndecl.  */
+  tree
+  build_trivial_high_gimple_function ()
+  {
+    /* Construct a trivial function, and gimplify it: */
+    tree fndecl = build_trivial_generic_function ();
+    gimplify_function_tree (fndecl);
+    return fndecl;
+  }
+
+  /* Build a CFG for a function in gimple form.  */
+  void
+  build_cfg (tree fndecl)
+  {
+    function *fun = DECL_STRUCT_FUNCTION (fndecl);
+    ASSERT_TRUE (fun != NULL);
+    EXPECT_EQ (fndecl, fun->decl);
+
+    /* We first have to lower control flow; for our trivial test function
+       this gives us:
+	 test_fn ()
+	 {
+	   D.56 = 42;
+	   goto <D.57>;
+	   <D.57>:
+	   return D.56;
+	 }
+    */
+    gimple_opt_pass *lower_cf_pass = make_pass_lower_cf (g);
+    push_cfun (fun);
+    lower_cf_pass->execute (fun);
+    pop_cfun ();
+
+    /* We can now convert to CFG form; for our trivial test function this
+       gives us:
+	 test_fn ()
+	 {
+	   <bb 2>:
+	   D.56 = 42;
+	   return D.56;
+	 }
+    */
+    gimple_opt_pass *build_cfg_pass = make_pass_build_cfg (g);
+    push_cfun (fun);
+    build_cfg_pass->execute (fun);
+    pop_cfun ();
+  }
+
+  /* Convert a gimple+CFG function to SSA form.  */
+  void
+  convert_to_ssa (tree fndecl)
+  {
+    function *fun = DECL_STRUCT_FUNCTION (fndecl);
+    ASSERT_TRUE (fun != NULL);
+    EXPECT_EQ (fndecl, fun->decl);
+
+    gimple_opt_pass *pass_init_datastructures =
+      make_pass_init_datastructures (g);
+    gimple_opt_pass *build_ssa_pass = make_pass_build_ssa (g);
+    push_cfun (fun);
+    pass_init_datastructures->execute (fun);
+    build_ssa_pass->execute (fun);
+    pop_cfun ();
+  }
+
+  /* Assuming we have a simple 3-block CFG like this:
+       [ENTRY] -> [block2] -> [EXIT]
+     get the "real" basic block (block 2).  */
+  basic_block
+  get_real_block (function *fun)
+  {
+    EXPECT_TRUE (fun->cfg != NULL);
+    EXPECT_EQ (3, n_basic_blocks_for_fn (fun));
+    basic_block bb2 = (*fun->cfg->x_basic_block_info)[2];
+    EXPECT_TRUE (bb2 != NULL);
+    return bb2;
+  }
+
+  /* Verify that we have a simple 3-block CFG: the two "fake" ones, and
+     a "real" one:
+     [ENTRY] -> [block2] -> [EXIT].  */
+  void
+  verify_three_block_cfg (function *fun)
+  {
+    ASSERT_TRUE (fun->cfg != NULL);
+    EXPECT_EQ (3, n_basic_blocks_for_fn (fun));
+    EXPECT_EQ (2, n_edges_for_fn (fun));
+
+    /* The "fake" basic blocks.  */
+    basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (entry != NULL);
+    EXPECT_EQ (ENTRY_BLOCK, entry->index);
+
+    basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (exit != NULL);
+    EXPECT_EQ (EXIT_BLOCK, exit->index);
+
+    /* The "real" basic block.  */
+    basic_block bb2 = get_real_block (fun);
+    ASSERT_TRUE (bb2 != NULL);
+    EXPECT_EQ (2, bb2->index);
+
+    /* Verify connectivity.  */
+    EXPECT_EQ (NULL, entry->preds);
+    EXPECT_EQ (1, entry->succs->length ());
+
+    edge from_entry_to_bb2 = (*entry->succs)[0];
+    EXPECT_EQ (entry, from_entry_to_bb2->src);
+    EXPECT_EQ (bb2, from_entry_to_bb2->dest);
+
+    EXPECT_EQ (1, bb2->preds->length ());
+    EXPECT_EQ (from_entry_to_bb2, (*bb2->preds)[0]);
+    EXPECT_EQ (1, bb2->succs->length ());
+
+    edge from_bb2_to_exit = (*bb2->succs)[0];
+    EXPECT_EQ (bb2, from_bb2_to_exit->src);
+    EXPECT_EQ (exit, from_bb2_to_exit->dest);
+
+    EXPECT_EQ (1, exit->preds->length ());
+    EXPECT_EQ (from_bb2_to_exit, (*exit->preds)[0]);
+    EXPECT_EQ (NULL, exit->succs);
+  }
+
+  /* As above, but additionally verify the gimple statements are sane.  */
+  void
+  verify_three_block_gimple_cfg (function *fun)
+  {
+    verify_three_block_cfg (fun);
+
+    /* The "fake" basic blocks should be flagged as gimple, but with have no
+       statements.  */
+    basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (entry != NULL);
+    EXPECT_EQ (0, entry->flags & BB_RTL);
+    EXPECT_EQ (NULL, bb_seq (entry));
+
+    basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (exit != NULL);
+    EXPECT_EQ (0, entry->flags & BB_RTL);
+    EXPECT_EQ (NULL, bb_seq (exit));
+
+    /* The "real" basic block should be flagged as gimple, and have one
+       or more statements.  */
+    basic_block bb2 = get_real_block (fun);
+    ASSERT_TRUE (bb2 != NULL);
+    EXPECT_EQ (0, entry->flags & BB_RTL);
+    EXPECT_TRUE (bb_seq (bb2) != NULL);
+  }
+
+  /* As above, but additionally verify the RTL insns are sane.  */
+  void
+  verify_three_block_rtl_cfg (function *fun)
+  {
+    verify_three_block_cfg (fun);
+
+    /* The "fake" basic blocks should be flagged as RTL, but with no
+       insns.  */
+    basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (entry != NULL);
+    EXPECT_EQ (BB_RTL, entry->flags & BB_RTL);
+    EXPECT_EQ (NULL, BB_HEAD (entry));
+
+    basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (exit != NULL);
+    EXPECT_EQ (BB_RTL, entry->flags & BB_RTL);
+    EXPECT_EQ (NULL, BB_HEAD (exit));
+
+    /* The "real" basic block should be flagged as RTL, and have one
+       or more insns.  */
+    basic_block bb2 = get_real_block (fun);
+    ASSERT_TRUE (bb2 != NULL);
+    EXPECT_EQ (BB_RTL, entry->flags & BB_RTL);
+    EXPECT_TRUE (BB_HEAD (bb2) != NULL);
+  }
+
+};
+
+/* Test converting our trivial function:
+     int test_fn (void) { return 42; }
+   to gimple form.  */
+
+TEST_F (representation_test, gimplification)
+{
+  tree fndecl = build_trivial_generic_function ();
+
+  /* Convert to gimple: */
+  gimplify_function_tree (fndecl);
+
+  /* Verify that we got gimple out of it.  */
+
+  /* The function is now in GIMPLE form but the CFG has not been
+     built yet.  */
+
+  /* We should have a struct function for the decl.  */
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  EXPECT_EQ (fndecl, fun->decl);
+
+  /* We expect a GIMPLE_BIND, with two gimple statements within it:
+       tmp = 42;
+       return tmp;  */
+
+  gimple_seq seq_fn_body = gimple_body (fndecl);
+  EXPECT_TRUE (seq_fn_body != NULL);
+  gimple *bind_stmt = gimple_seq_first_stmt (seq_fn_body);
+  EXPECT_EQ (GIMPLE_BIND, gimple_code (bind_stmt));
+  EXPECT_EQ (NULL, bind_stmt->next);
+
+  gimple_seq seq_bind_body = gimple_bind_body (as_a <gbind *> (bind_stmt));
+
+  /* Verify that we have the 2 statements we expect.  */
+  EXPECT_TRUE (seq_bind_body != NULL);
+  gimple *stmt1 = gimple_seq_first_stmt (seq_bind_body);
+  ASSERT_TRUE (stmt1 != NULL);
+  EXPECT_EQ (GIMPLE_ASSIGN, gimple_code (stmt1));
+  gimple *stmt2 = stmt1->next;
+  ASSERT_TRUE (stmt2 != NULL);
+  EXPECT_EQ (stmt1, stmt2->prev);
+  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt2));
+}
+
+/* Test of building a CFG for a function in high gimple form.  */
+
+TEST_F (representation_test, building_cfg)
+{
+  /* Construct a trivial function, and gimplify it: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+
+  /* Build a CFG.  */
+  build_cfg (fndecl);
+
+  /* The CFG-building code constructs a 4-block cfg (with
+     ENTRY and EXIT):
+       test_fn ()
+       {
+         <bb 2>:
+	 D.65 = 42;
+
+	 <bb 3>:
+	 return D.65;
+       }
+     and then ought to merge blocks 2 and 3 in cleanup_tree_cfg.
+
+     Hence we should end up with a simple 3-block cfg, the two "fake" ones,
+     and a "real" one:
+       [ENTRY] -> [block2] -> [EXIT]
+     with code like this:
+	 test_fn ()
+	 {
+	   <bb 2>:
+	   D.56 = 42;
+	   return D.56;
+	 }
+  */
+  verify_three_block_gimple_cfg (fun);
+
+  /* Verify the statements within the "real" block.  */
+  basic_block bb2 = get_real_block (fun);
+  gimple *stmt_a = gimple_seq_first_stmt (bb_seq (bb2));
+  EXPECT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a));
+  gimple *stmt_b = stmt_a->next;
+  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt_b));
+  EXPECT_EQ (NULL, stmt_b->next);
+}
+
+/* Test of conversion of gimple to SSA form.  */
+TEST_F (representation_test, conversion_to_ssa)
+{
+  /* As above, construct a trivial function, gimplify it, and build a CFG: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  build_cfg (fndecl);
+
+  convert_to_ssa (fndecl);
+
+  verify_three_block_gimple_cfg (fun);
+
+  /* For out trivial test function we should now have something like
+     this:
+       test_fn ()
+       {
+	 <bb 2>:
+	 _1 = 42;
+	 return _1;
+       }
+  */
+  basic_block bb2 = get_real_block (fun);
+  gimple *stmt_a = gimple_seq_first_stmt (bb_seq (bb2));
+  EXPECT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a));
+
+  gimple *stmt_b = stmt_a->next;
+  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt_b));
+  EXPECT_EQ (NULL, stmt_b->next);
+
+  greturn *return_stmt = as_a <greturn *> (stmt_b);
+  EXPECT_EQ (SSA_NAME, TREE_CODE (gimple_return_retval (return_stmt)));
+}
+
+/* Test of expansion from gimple-ssa to RTL.  */
+
+TEST_F (representation_test, expansion_to_rtl)
+{
+  /* As above, construct a trivial function, gimplify it, build a CFG,
+     and convert to SSA: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  build_cfg (fndecl);
+  convert_to_ssa (fndecl);
+
+  /* We need a cgraph_node for it.  */
+  cgraph_node::get_create (fndecl);
+  /* Normally, cgraph_node::expand () would call
+     init_function_start (and a bunch of other stuff),
+     and invoke the expand pass, but it also runs
+     all of the other passes.  So just do the minimum
+     needed to get from gimple-SSA to RTL.  */
+  rtl_opt_pass *expand_pass = make_pass_expand (g);
+  push_cfun (fun);
+  init_function_start (fndecl);
+  expand_pass->execute (fun);
+  pop_cfun ();
+
+  /* On x86_64, I get this:
+       (note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+       (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
+       (insn 5 2 6 2 (set (reg:SI 87 [ D.59 ])
+			  (const_int 42 [0x2a])) -1 (nil))
+       (insn 6 5 10 2 (set (reg:SI 88 [ <retval> ])
+			   (reg:SI 87 [ D.59 ])) -1 (nil))
+       (insn 10 6 11 2 (set (reg/i:SI 0 ax)
+			    (reg:SI 88 [ <retval> ])) -1 (nil))
+       (insn 11 10 0 2 (use (reg/i:SI 0 ax)) -1 (nil))
+   */
+  verify_three_block_rtl_cfg (fun);
+
+  /* Verify as much of the RTL as we can whilst avoiding
+     target-specific behavior.  */
+  basic_block bb2 = get_real_block (fun);
+
+  /* Expect a NOTE_INSN_BASIC_BLOCK... */
+  rtx_insn *insn = BB_HEAD (bb2);
+  ASSERT_TRUE (insn != NULL);
+  EXPECT_EQ (NOTE, insn->code);
+  EXPECT_EQ (NOTE_INSN_BASIC_BLOCK, NOTE_KIND (insn));
+  EXPECT_EQ (bb2, NOTE_BASIC_BLOCK (insn));
+
+  /* ...followed by a NOTE_INSN_FUNCTION_BEG...  */
+  insn = NEXT_INSN (insn);
+  ASSERT_TRUE (insn != NULL);
+  EXPECT_EQ (NOTE, insn->code);
+  EXPECT_EQ (NOTE_INSN_FUNCTION_BEG, NOTE_KIND (insn));
+
+  /* ...followed by a SET of a reg to the const value.  */
+  insn = NEXT_INSN (insn);
+  ASSERT_TRUE (insn != NULL);
+  EXPECT_EQ (INSN, insn->code);
+  rtx pat = PATTERN (insn);
+  ASSERT_TRUE (pat != NULL);
+  EXPECT_EQ (SET, pat->code);
+  EXPECT_EQ (REG, SET_DEST (pat)->code);
+  EXPECT_EQ (CONST_INT, SET_SRC (pat)->code);
+  EXPECT_EQ (42, INTVAL (SET_SRC (pat)));
+
+  /* ...etc; any further checks are likely to over-specify things
+     and run us into target dependencies.  */
+}
+
+}  // anon namespace
+
+#endif /* #if CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 15/15] RFC: Add ggc-tests.c
  2015-11-19 16:46                       ` [PATCH 00/15] Unittests framework v4: -fself-test David Malcolm
                                           ` (11 preceding siblings ...)
  2015-11-19 16:46                         ` [PATCH 04/15] Add selftests to et-forest.c David Malcolm
@ 2015-11-19 16:46                         ` David Malcolm
  2015-11-19 17:03                         ` [PATCH 12/15] Add rtl-tests.c David Malcolm
                                           ` (2 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-11-19 16:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-ggc.c):
  https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03306.html
> Not terribly happy with that counter to used to create a big list
> to detect recursion. But I'm not offhand sure how to avoid without
> exposing more of the ggc system that is wise.
>
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files is
> pre-approved.

This version moves it to gcc/gcc-tests.c.

For now, I also reduced the count within
  TEST_F (ggc_test, chain_next)
from 2 million to 10, to avoid swamping stderr with PASS results.

There's a problem with this test as-is: it adds GTY roots, but it's
all wrapped with #if CHECKING_P.  This leads to a failure at
link time when building with
  --enable-checking=release
since the various generated gtype-foo.c contain references to the
roots like this:

  /* ...snip.. */
  extern const struct ggc_root_tab gt_ggc_r_gt_ggc_tests_h[];
  /* ...snip.. */

  EXPORTED_CONST struct ggc_root_tab * const gt_ggc_rtab[] = {
    /* ...snip.. */
    gt_ggc_r_gt_ggc_tests_h,
    /* ...snip.. */
  };

etc.

(This could be special-cased in gengtype, I suppose, but do we want
to have such conditional roots?)

Potentially we could build up PCH testing here, in which case do we
want to have conditional roots?  In particular, that would mean PCH
files would be incompatible between release vs checked builds
(I'm not sure whether or not that's already the case).

Hence I'm deferring this one for now; if we resolve the issues it
could be committed separately to the other patches.

gcc/ChangeLog:
	* Makefile.in (OBJS): Add ggc-tests.o.
	(GTFILES): Add ggc-tests.c.
	* ggc-tests.c: New file.
---
 gcc/Makefile.in |   2 +
 gcc/ggc-tests.c | 302 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 304 insertions(+)
 create mode 100644 gcc/ggc-tests.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index ebc9dee..657aaac 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1267,6 +1267,7 @@ OBJS = \
 	gcse.o \
 	gcse-common.o \
 	ggc-common.o \
+	ggc-tests.o \
 	gimple.o \
 	gimple-builder.o \
 	gimple-expr.o \
@@ -2366,6 +2367,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(srcdir)/emit-rtl.c $(srcdir)/except.h $(srcdir)/explow.c $(srcdir)/expr.c \
   $(srcdir)/expr.h \
   $(srcdir)/function.c $(srcdir)/except.c \
+  $(srcdir)/ggc-tests.c \
   $(srcdir)/gcse.c $(srcdir)/godump.c \
   $(srcdir)/lists.c $(srcdir)/optabs-libfuncs.c \
   $(srcdir)/profile.c $(srcdir)/mcf.c \
diff --git a/gcc/ggc-tests.c b/gcc/ggc-tests.c
new file mode 100644
index 0000000..ed6cbe6
--- /dev/null
+++ b/gcc/ggc-tests.c
@@ -0,0 +1,302 @@
+/* Unit tests for GCC's garbage collector (and gengtype etc).
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "ggc-internal.h" /* (for ggc_force_collect).  */
+
+#include "selftest.h"
+
+#if CHECKING_P
+
+/* The various GTY markers must be outside of a namespace to be seen by
+   gengtype, so we don't put this file within an anonymous namespace.  */
+
+/* A test fixture for writing ggc tests.  */
+class ggc_test : public ::selftest::test
+{
+ protected:
+  void
+  forcibly_ggc_collect ()
+  {
+    ggc_force_collect = true;
+    ggc_collect ();
+    ggc_force_collect = false;
+  }
+};
+
+/* Smoketest to ensure that a GC root is marked ("tree" type).  */
+
+static GTY(()) tree dummy_unittesting_tree;
+
+TEST_F (ggc_test, tree_marking)
+{
+  dummy_unittesting_tree = build_int_cst (integer_type_node, 1066);
+
+  forcibly_ggc_collect ();
+
+  EXPECT_TRUE (ggc_marked_p (dummy_unittesting_tree));
+}
+
+/* Verify that a simple custom struct works, and that it can
+   own references to non-roots, and have them be marked.  */
+
+struct GTY(()) test_struct
+{
+  test_struct *other;
+};
+
+static GTY(()) test_struct *root_test_struct;
+
+TEST_F (ggc_test, custom_struct)
+{
+  root_test_struct = ggc_cleared_alloc <test_struct> ();
+  root_test_struct->other = ggc_cleared_alloc <test_struct> ();
+
+  forcibly_ggc_collect ();
+
+  EXPECT_TRUE (ggc_marked_p (root_test_struct));
+  EXPECT_TRUE (ggc_marked_p (root_test_struct->other));
+}
+
+/* Verify that destructors get run when instances are collected.  */
+
+struct GTY(()) test_struct_with_dtor
+{
+  /* This struct has a destructor; it *ought* to be called
+     by the ggc machinery when instances are collected.  */
+  ~test_struct_with_dtor () { dtor_call_count++; }
+
+  static int dtor_call_count;
+};
+
+int test_struct_with_dtor::dtor_call_count;
+
+TEST_F (ggc_test, finalization)
+{
+  EXPECT_FALSE (need_finalization_p <test_struct> ());
+  EXPECT_TRUE (need_finalization_p <test_struct_with_dtor> ());
+
+  /* Create some garbage.  */
+  const int count = 10;
+  for (int i = 0; i < count; i++)
+    ggc_cleared_alloc <test_struct_with_dtor> ();
+
+  test_struct_with_dtor::dtor_call_count = 0;
+
+  forcibly_ggc_collect ();
+
+  /* Verify that the destructor was run for each instance.  */
+  EXPECT_EQ (count, test_struct_with_dtor::dtor_call_count);
+}
+
+/* Verify that a global can be marked as "deletable".  */
+
+static GTY((deletable)) test_struct *test_of_deletable;
+
+/* FIXME: we can't do this test via a plugin as it stands.
+   The list of deletable roots is fixed by the main gengtype
+   run; there isn't yet a way to add extra
+   deletable roots (PLUGIN_REGISTER_GGC_ROOTS is for regular
+   roots).  */
+#if 0
+TEST_F (ggc_test, deletable_global)
+{
+  test_of_deletable = ggc_cleared_alloc <test_struct> ();
+  EXPECT_TRUE (test_of_deletable != NULL);
+
+  forcibly_ggc_collect ();
+
+  EXPECT_EQ (NULL, test_of_deletable);
+}
+#endif
+
+/* Verify that gengtype etc can cope with inheritance.  */
+
+class GTY((desc("%h.m_kind"), tag("0"))) example_base
+{
+ public:
+  example_base ()
+    : m_kind (0),
+      m_a (ggc_cleared_alloc <test_struct> ())
+  {}
+
+  void *
+  operator new (size_t sz)
+  {
+    return ggc_internal_cleared_alloc (sz);
+  }
+
+ protected:
+  example_base (int kind)
+    : m_kind (kind),
+      m_a (ggc_cleared_alloc <test_struct> ())
+  {}
+
+ public:
+  int m_kind;
+  test_struct *m_a;
+};
+
+class GTY((tag("1"))) some_subclass : public example_base
+{
+ public:
+  some_subclass ()
+    : example_base (1),
+      m_b (ggc_cleared_alloc <test_struct> ())
+  {}
+
+  test_struct *m_b;
+};
+
+class GTY((tag("2"))) some_other_subclass : public example_base
+{
+ public:
+  some_other_subclass ()
+    : example_base (2),
+      m_c (ggc_cleared_alloc <test_struct> ())
+  {}
+
+  test_struct *m_c;
+};
+
+/* Various test roots, both expressed as a ptr to the actual class, and
+   as a ptr to the base class.  */
+static GTY(()) example_base *test_example_base;
+static GTY(()) some_subclass *test_some_subclass;
+static GTY(()) some_other_subclass *test_some_other_subclass;
+static GTY(()) example_base *test_some_subclass_as_base_ptr;
+static GTY(()) example_base *test_some_other_subclass_as_base_ptr;
+
+TEST_F (ggc_test, inheritance)
+{
+  test_example_base = new example_base ();
+  test_some_subclass = new some_subclass ();
+  test_some_other_subclass = new some_other_subclass ();
+  test_some_subclass_as_base_ptr = new some_subclass ();
+  test_some_other_subclass_as_base_ptr = new some_other_subclass ();
+
+  forcibly_ggc_collect ();
+
+  /* Verify that the roots and everything referenced by them got marked
+     (both for fields in the base class and those in subclasses).  */
+  EXPECT_TRUE (ggc_marked_p (test_example_base));
+  EXPECT_TRUE (ggc_marked_p (test_example_base->m_a));
+
+  EXPECT_TRUE (ggc_marked_p (test_some_subclass));
+  EXPECT_TRUE (ggc_marked_p (test_some_subclass->m_a));
+  EXPECT_TRUE (ggc_marked_p (test_some_subclass->m_b));
+
+  EXPECT_TRUE (ggc_marked_p (test_some_other_subclass));
+  EXPECT_TRUE (ggc_marked_p (test_some_other_subclass->m_a));
+  EXPECT_TRUE (ggc_marked_p (test_some_other_subclass->m_c));
+
+  EXPECT_TRUE (ggc_marked_p (test_some_subclass_as_base_ptr));
+  EXPECT_TRUE (ggc_marked_p (test_some_subclass_as_base_ptr->m_a));
+  EXPECT_TRUE (ggc_marked_p (((some_subclass *)
+			      test_some_subclass_as_base_ptr)->m_b));
+
+  EXPECT_TRUE (ggc_marked_p (test_some_other_subclass_as_base_ptr));
+  EXPECT_TRUE (ggc_marked_p (test_some_other_subclass_as_base_ptr->m_a));
+  EXPECT_TRUE (ggc_marked_p (((some_other_subclass *)
+			      test_some_other_subclass_as_base_ptr)->m_c));
+}
+
+/* Test of chain_next/chain_prev
+
+   Construct a very long linked list, so that without
+   the chain_next/chain_prev optimization we'd have
+   a stack overflow when gt_ggc_mx_test_node recurses.  */
+
+struct GTY(( chain_next ("%h.m_next"),
+	     chain_prev ("%h.m_prev") )) test_node
+{
+  test_node *m_prev;
+  test_node *m_next;
+  int m_idx;
+};
+
+static GTY(()) test_node *root_test_node;
+
+TEST_F (ggc_test, chain_next)
+{
+  /* 2 million nodes (and thus the same number of stack frames) ought
+     to be deep enough to crash if gengtype has created something
+     that recurses.
+
+     This length reliably causes the test to segfault without the
+     chain_next/prev optimization on this box (Fedora 20 x86_64 with 128GB
+     of RAM), but causes this test to take about 0.5s, dominating the time
+     taken by the overall testsuite.
+
+     We could perhaps lower this by not increasing the stack size so much
+     in toplev.c, or perhaps reducing the stack size when running this
+     testcase.  */
+  const int count = 10; // 2000000;
+
+  /* Build the linked list.  */
+  root_test_node = ggc_cleared_alloc <test_node> ();
+  test_node *tail_node = root_test_node;
+  for (int i = 0; i < count; i++)
+    {
+      test_node *new_node = ggc_cleared_alloc <test_node> ();
+      tail_node->m_next = new_node;
+      new_node->m_prev = tail_node;
+      new_node->m_idx = i;
+      tail_node = new_node;
+    }
+
+  forcibly_ggc_collect ();
+
+  /* If we got here, we survived.  */
+
+  /* Verify that all nodes in the list were marked.  */
+  EXPECT_TRUE (ggc_marked_p (root_test_node));
+  test_node *iter_node = root_test_node->m_next;
+  for (int i = 0; i < count; i++)
+    {
+      EXPECT_TRUE (ggc_marked_p (iter_node));
+      EXPECT_EQ (i, iter_node->m_idx);
+      iter_node = iter_node->m_next;
+    }
+}
+
+/* Ideas for other tests:
+   - pch-handling  */
+
+#include "gt-ggc-tests.h"
+
+#endif /* #if CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 08/15] Add selftests to gimple.c
  2015-11-19 16:46                       ` [PATCH 00/15] Unittests framework v4: -fself-test David Malcolm
  2015-11-19 16:46                         ` [PATCH 07/15] Fix warning in function-tests.c David Malcolm
  2015-11-19 16:46                         ` [PATCH 03/15] Add selftests to tree-cfg.c David Malcolm
@ 2015-11-19 16:46                         ` David Malcolm
  2015-11-19 16:46                         ` [PATCH 02/15] Add selftests to bitmap.c David Malcolm
                                           ` (12 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-11-19 16:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-gimple.c):
 https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03304.html

> Comment indicates addition. But code actually generates a
> MULT_EXPR. Please fix.
Fixed

> OK if/when prereqs are approved. Minor twiddling if we end
> up moving it elsewhere or standardizing/reducing header files
> is pre-approved.

This version moves the tests into gimple.c.

gcc/ChangeLog:
	* gimple.c: Include "selftest.h".
	Include "gimple-pretty-print.h".
	(class gimple_test): New subclass.
	(gimple_test, assign_single): New selftest.
	(gimple_test, assign_binop): New selftest.
	(gimple_test, nop_stmt): New selftest.
	(gimple_test, return_stmt): New selftest.
	(gimple_test, return_without_value): New selftest.
---
 gcc/gimple.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 103 insertions(+)

diff --git a/gcc/gimple.c b/gcc/gimple.c
index 2764df8..17d3896 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-walk.h"
 #include "gimplify.h"
 #include "target.h"
+#include "selftest.h"
+#include "gimple-pretty-print.h"
 
 
 /* All the tuples have their operand vector (if present) at the very bottom
@@ -2990,3 +2992,104 @@ maybe_remove_unused_call_args (struct function *fn, gimple *stmt)
       update_stmt_fn (fn, stmt);
     }
 }
+
+#if CHECKING_P
+
+namespace {
+
+class gimple_test : public ::selftest::test
+{
+ protected:
+  void
+  verify_gimple_pp (const char *expected, gimple *stmt)
+  {
+    pretty_printer pp;
+    pp_gimple_stmt_1 (&pp, stmt, 0 /* spc */, 0 /* flags */);
+    EXPECT_STREQ (expected, pp_formatted_text (&pp));
+  }
+};
+
+TEST_F (gimple_test, assign_single)
+{
+  /* Build "tmp = 5;"  */
+  tree type = integer_type_node;
+  tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			 get_identifier ("tmp"),
+			 type);
+  tree rhs = build_int_cst (type, 5);
+  gassign *stmt = gimple_build_assign (lhs, rhs);
+  verify_gimple_pp ("tmp = 5;", stmt);
+
+  EXPECT_TRUE (is_gimple_assign (stmt));
+  EXPECT_EQ (lhs, gimple_assign_lhs (stmt));
+  EXPECT_EQ (lhs, gimple_get_lhs (stmt));
+  EXPECT_EQ (rhs, gimple_assign_rhs1 (stmt));
+  EXPECT_EQ (NULL, gimple_assign_rhs2 (stmt));
+  EXPECT_EQ (NULL, gimple_assign_rhs3 (stmt));
+  EXPECT_TRUE (gimple_assign_single_p (stmt));
+  EXPECT_EQ (INTEGER_CST, gimple_assign_rhs_code (stmt));
+}
+
+TEST_F (gimple_test, assign_binop)
+{
+  /* Build "tmp = a * b;"  */
+  tree type = integer_type_node;
+  tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			 get_identifier ("tmp"),
+			 type);
+  tree a = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		       get_identifier ("a"),
+		       type);
+  tree b = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		       get_identifier ("b"),
+		       type);
+  gassign *stmt = gimple_build_assign (lhs, MULT_EXPR, a, b);
+  verify_gimple_pp ("tmp = a * b;", stmt);
+
+  EXPECT_TRUE (is_gimple_assign (stmt));
+  EXPECT_EQ (lhs, gimple_assign_lhs (stmt));
+  EXPECT_EQ (lhs, gimple_get_lhs (stmt));
+  EXPECT_EQ (a, gimple_assign_rhs1 (stmt));
+  EXPECT_EQ (b, gimple_assign_rhs2 (stmt));
+  EXPECT_EQ (NULL, gimple_assign_rhs3 (stmt));
+  EXPECT_FALSE (gimple_assign_single_p (stmt));
+  EXPECT_EQ (MULT_EXPR, gimple_assign_rhs_code (stmt));
+}
+
+TEST_F (gimple_test, nop_stmt)
+{
+  gimple *stmt = gimple_build_nop ();
+  verify_gimple_pp ("GIMPLE_NOP", stmt);
+  EXPECT_EQ (GIMPLE_NOP, gimple_code (stmt));
+  EXPECT_EQ (NULL, gimple_get_lhs (stmt));
+  EXPECT_FALSE (gimple_assign_single_p (stmt));
+}
+
+TEST_F (gimple_test, return_stmt)
+{
+  /* Build "return 7;"  */
+  tree type = integer_type_node;
+  tree val = build_int_cst (type, 7);
+  greturn *stmt = gimple_build_return (val);
+  verify_gimple_pp ("return 7;", stmt);
+
+  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt));
+  EXPECT_EQ (NULL, gimple_get_lhs (stmt));
+  EXPECT_EQ (val, gimple_return_retval (stmt));
+  EXPECT_FALSE (gimple_assign_single_p (stmt));
+}
+
+TEST_F (gimple_test, return_without_value)
+{
+  greturn *stmt = gimple_build_return (NULL);
+  verify_gimple_pp ("return;", stmt);
+
+  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt));
+  EXPECT_EQ (NULL, gimple_get_lhs (stmt));
+  EXPECT_EQ (NULL, gimple_return_retval (stmt));
+  EXPECT_FALSE (gimple_assign_single_p (stmt));
+}
+
+}  /* anon namespace.  */
+
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 03/15] Add selftests to tree-cfg.c
  2015-11-19 16:46                       ` [PATCH 00/15] Unittests framework v4: -fself-test David Malcolm
  2015-11-19 16:46                         ` [PATCH 07/15] Fix warning in function-tests.c David Malcolm
@ 2015-11-19 16:46                         ` David Malcolm
  2015-11-19 16:46                         ` [PATCH 08/15] Add selftests to gimple.c David Malcolm
                                           ` (13 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-11-19 16:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an older version of this:
  https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03285.html
with:
> Unless there's a good reason, drop the presumably redundant tests
> and this is OK. Save preapprovald for these changes as the bitmap
> patch.

This version removes the redundant tests, and moves the tests
from being in a new file to being in tree-cfg.c

gcc/ChangeLog:
	* tree-cfg.c: Include "selftest.h".
	(class cfg_test): New test subclass.
	(cfg_test, linear_chain): New selftest.
	(cfg_test, diamond): New selftest.
	(cfg_test, fully_connected): New selftest.
---
 gcc/tree-cfg.c | 264 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 264 insertions(+)

diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 0c624aa..797cce3 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -58,6 +58,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-cfgcleanup.h"
 #include "gimplify.h"
 #include "attribs.h"
+#include "selftest.h"
 
 /* This file contains functions for building the Control Flow Graph (CFG)
    for a function tree.  */
@@ -9011,3 +9012,266 @@ gt_pch_nx (edge_def *e, gt_pointer_operator op, void *cookie)
     op (&(e->insns.r), cookie);
   op (&(block), cookie);
 }
+
+#if CHECKING_P
+
+namespace {
+
+class cfg_test : public ::selftest::test
+{
+ protected:
+  tree
+  push_fndecl (const char *name)
+  {
+    tree fn_type = build_function_type_array (integer_type_node, /* return_type */
+					    0, NULL);
+    /* FIXME: this uses input_location: */
+    tree fndecl = build_fn_decl (name, fn_type);
+    tree retval = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+			      NULL_TREE, integer_type_node);
+    DECL_RESULT (fndecl) = retval;
+    push_struct_function (fndecl);
+    function *fun = DECL_STRUCT_FUNCTION (fndecl);
+    EXPECT_TRUE (fun != NULL);
+    init_empty_tree_cfg_for_function (fun);
+    EXPECT_EQ (2, n_basic_blocks_for_fn (fun));
+    EXPECT_EQ (0, n_edges_for_fn (fun));
+    return fndecl;
+  }
+};
+
+/* These tests directly create CFGs.
+   Compare with the static fns within tree-cfg.c:
+     - build_gimple_cfg
+     - make_blocks: calls create_basic_block (seq, bb);
+     - make_edges.   */
+
+/* Verify a simple cfg of the form:
+     ENTRY -> A -> B -> C -> EXIT.  */
+TEST_F (cfg_test, linear_chain)
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_test_linear_chain");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+
+  /* Create some empty blocks.  */
+  basic_block bb_a = create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun));
+  basic_block bb_b = create_empty_bb (bb_a);
+  basic_block bb_c = create_empty_bb (bb_b);
+
+  EXPECT_EQ (5, n_basic_blocks_for_fn (fun));
+  EXPECT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create some edges: a simple linear chain of BBs.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), bb_a, EDGE_FALLTHRU);
+  make_edge (bb_a, bb_b, 0);
+  make_edge (bb_b, bb_c, 0);
+  make_edge (bb_c, EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+
+  /* Verify the edges.  */
+  EXPECT_EQ (4, n_edges_for_fn (fun));
+  EXPECT_EQ (NULL, ENTRY_BLOCK_PTR_FOR_FN (fun)->preds);
+  EXPECT_EQ (1, ENTRY_BLOCK_PTR_FOR_FN (fun)->succs->length ());
+  EXPECT_EQ (1, bb_a->preds->length ());
+  EXPECT_EQ (1, bb_a->succs->length ());
+  EXPECT_EQ (1, bb_b->preds->length ());
+  EXPECT_EQ (1, bb_b->succs->length ());
+  EXPECT_EQ (1, bb_c->preds->length ());
+  EXPECT_EQ (1, bb_c->succs->length ());
+  EXPECT_EQ (1, EXIT_BLOCK_PTR_FOR_FN (fun)->preds->length ());
+  EXPECT_EQ (NULL, EXIT_BLOCK_PTR_FOR_FN (fun)->succs);
+
+  /* Verify the dominance information
+     Each BB in our simple chain should be dominated by the one before
+     it.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  EXPECT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
+  EXPECT_EQ (bb_b, get_immediate_dominator (CDI_DOMINATORS, bb_c));
+  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
+  EXPECT_EQ (1, dom_by_b.length ());
+  EXPECT_EQ (bb_c, dom_by_b[0]);
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance: each BB in our chain is post-dominated
+     by the one after it.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  EXPECT_EQ (bb_b, get_immediate_dominator (CDI_POST_DOMINATORS, bb_a));
+  EXPECT_EQ (bb_c, get_immediate_dominator (CDI_POST_DOMINATORS, bb_b));
+  vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
+  EXPECT_EQ (1, postdom_by_b.length ());
+  EXPECT_EQ (bb_a, postdom_by_b[0]);
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+/* Verify a simple CFG of the form:
+     ENTRY
+       |
+       A
+      / \
+     /t  \f
+    B     C
+     \   /
+      \ /
+       D
+       |
+      EXIT.  */
+TEST_F (cfg_test, diamond)
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_test_diamond");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+
+  /* Create some empty blocks.  */
+  basic_block bb_a = create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun));
+  basic_block bb_b = create_empty_bb (bb_a);
+  basic_block bb_c = create_empty_bb (bb_a);
+  basic_block bb_d = create_empty_bb (bb_b);
+
+  EXPECT_EQ (6, n_basic_blocks_for_fn (fun));
+  EXPECT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create the edges.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), bb_a, EDGE_FALLTHRU);
+  make_edge (bb_a, bb_b, EDGE_TRUE_VALUE);
+  make_edge (bb_a, bb_c, EDGE_FALSE_VALUE);
+  make_edge (bb_b, bb_d, 0);
+  make_edge (bb_c, bb_d, 0);
+  make_edge (bb_d, EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+
+  /* Verify the edges.  */
+  EXPECT_EQ (6, n_edges_for_fn (fun));
+  EXPECT_EQ (1, bb_a->preds->length ());
+  EXPECT_EQ (2, bb_a->succs->length ());
+  EXPECT_EQ (1, bb_b->preds->length ());
+  EXPECT_EQ (1, bb_b->succs->length ());
+  EXPECT_EQ (1, bb_c->preds->length ());
+  EXPECT_EQ (1, bb_c->succs->length ());
+  EXPECT_EQ (2, bb_d->preds->length ());
+  EXPECT_EQ (1, bb_d->succs->length ());
+
+  /* Verify the dominance information.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  EXPECT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
+  EXPECT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_c));
+  EXPECT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_d));
+  vec<basic_block> dom_by_a = get_dominated_by (CDI_DOMINATORS, bb_a);
+  EXPECT_EQ (3, dom_by_a.length ()); /* B, C, D, in some order.  */
+  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
+  EXPECT_EQ (0, dom_by_b.length ());
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  EXPECT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_a));
+  EXPECT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_b));
+  EXPECT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_c));
+  vec<basic_block> postdom_by_d = get_dominated_by (CDI_POST_DOMINATORS, bb_d);
+  EXPECT_EQ (3, postdom_by_d.length ()); /* A, B, C in some order.  */
+  vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
+  EXPECT_EQ (0, postdom_by_b.length ());
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+/* Verify that we can handle a CFG containing a "complete" aka
+   fully-connected subgraph (where A B C D below all have edges
+   pointing to each other node, also to themselves).
+   e.g.:
+     ENTRY  EXIT
+       |    ^
+       |   /
+       |  /
+       | /
+       V/
+       A<--->B
+       ^^   ^^
+       | \ / |
+       |  X  |
+       | / \ |
+       VV   VV
+       C<--->D
+*/
+TEST_F (cfg_test, fully_connected)
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_fully_connected");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+
+  const int n = 4;
+
+  /* Create some empty blocks.  */
+  auto_vec <basic_block> subgraph_nodes;
+  for (int i = 0; i < n; i++)
+    subgraph_nodes.safe_push (create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun)));
+
+  EXPECT_EQ (n + 2, n_basic_blocks_for_fn (fun));
+  EXPECT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create the edges.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), subgraph_nodes[0], EDGE_FALLTHRU);
+  make_edge (subgraph_nodes[0], EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+  for (int i = 0; i < n; i++)
+    for (int j = 0; j < n; j++)
+      make_edge (subgraph_nodes[i], subgraph_nodes[j], 0);
+
+  /* Verify the edges.  */
+  EXPECT_EQ (2 + (n * n), n_edges_for_fn (fun));
+  /* The first one is linked to ENTRY/EXIT as well as itself and
+     everything else.  */
+  EXPECT_EQ (n + 1, subgraph_nodes[0]->preds->length ());
+  EXPECT_EQ (n + 1, subgraph_nodes[0]->succs->length ());
+  /* The other ones in the subgraph are linked to everything in
+     the subgraph (including themselves).  */
+  for (int i = 1; i < n; i++)
+    {
+      EXPECT_EQ (n, subgraph_nodes[i]->preds->length ());
+      EXPECT_EQ (n, subgraph_nodes[i]->succs->length ());
+    }
+
+  /* Verify the dominance information.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  /* The initial block in the subgraph should be dominated by ENTRY.  */
+  EXPECT_EQ (ENTRY_BLOCK_PTR_FOR_FN (fun),
+	     get_immediate_dominator (CDI_DOMINATORS,
+				      subgraph_nodes[0]));
+  /* Every other block in the subgraph should be dominated by the
+     initial block.  */
+  for (int i = 1; i < n; i++)
+    EXPECT_EQ (subgraph_nodes[0],
+	       get_immediate_dominator (CDI_DOMINATORS,
+					subgraph_nodes[i]));
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  /* The initial block in the subgraph should be postdominated by EXIT.  */
+  EXPECT_EQ (EXIT_BLOCK_PTR_FOR_FN (fun),
+	     get_immediate_dominator (CDI_POST_DOMINATORS,
+				      subgraph_nodes[0]));
+  /* Every other block in the subgraph should be postdominated by the
+     initial block, since that leads to EXIT.  */
+  for (int i = 1; i < n; i++)
+    EXPECT_EQ (subgraph_nodes[0],
+	       get_immediate_dominator (CDI_POST_DOMINATORS,
+					subgraph_nodes[i]));
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+}  /* anon namespace.  */
+
+/* TODO: test the dominator/postdominator logic with various graphs/nodes:
+   - loop
+   - nested loops
+   - switch statement (a block with many out-edges)
+   - something that jumps to itself
+   - etc  */
+
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 05/15] Add selftests to fold-const.c
  2015-11-19 16:46                       ` [PATCH 00/15] Unittests framework v4: -fself-test David Malcolm
                                           ` (3 preceding siblings ...)
  2015-11-19 16:46                         ` [PATCH 02/15] Add selftests to bitmap.c David Malcolm
@ 2015-11-19 16:46                         ` David Malcolm
  2015-11-19 16:46                         ` [PATCH 09/15] Add hash-map-tests.c David Malcolm
                                           ` (10 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-11-19 16:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an older version of this (as a separate
unittests/test-folding.c):
 https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03305.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files
> is pre-approved.

gcc/ChangeLog:
	* fold-const.c: Include "selftest.h".
	(class tree_folding_test): New test subclass.
	(tree_folding_test, arithmetic_folding): New selftest.
---
 gcc/fold-const.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)

diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 698062e..27c9216 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -74,6 +74,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-into-ssa.h"
 #include "md5.h"
 #include "case-cfn-macros.h"
+#include "selftest.h"
 
 #ifndef LOAD_EXTEND_OP
 #define LOAD_EXTEND_OP(M) UNKNOWN
@@ -14423,3 +14424,68 @@ c_getstr (tree src)
 
   return TREE_STRING_POINTER (src) + tree_to_uhwi (offset_node);
 }
+
+#if CHECKING_P
+
+namespace {
+
+/* A test fixture for writing tests of folding trees.  */
+class tree_folding_test : public ::selftest::test
+{
+ protected:
+  void
+  assert_binop_folds_to_const (tree lhs, enum tree_code code, tree rhs,
+			       tree constant)
+  {
+    EXPECT_EQ (constant, fold_build2 (code, TREE_TYPE (lhs), lhs, rhs));
+  }
+
+  void
+  assert_binop_folds_to_nonlvalue (tree lhs, enum tree_code code, tree rhs,
+				   tree wrapped_expr)
+  {
+    tree result = fold_build2 (code, TREE_TYPE (lhs), lhs, rhs);
+    EXPECT_NE (wrapped_expr, result);
+    EXPECT_EQ (NON_LVALUE_EXPR, TREE_CODE (result));
+    EXPECT_EQ (wrapped_expr, TREE_OPERAND (result, 0));
+  }
+};
+
+TEST_F (tree_folding_test, arithmetic_folding)
+{
+  tree type = integer_type_node;
+  tree x = create_tmp_var_raw (type, "x");
+  tree zero = build_zero_cst (type);
+  tree one = build_int_cst (type, 1);
+
+  /* Addition.  */
+  /* 1 <-- (0 + 1) */
+  assert_binop_folds_to_const (zero, PLUS_EXPR, one,
+			       one);
+  assert_binop_folds_to_const (one, PLUS_EXPR, zero,
+			       one);
+
+  /* (nonlvalue)x <-- (x + 0) */
+  assert_binop_folds_to_nonlvalue (x, PLUS_EXPR, zero,
+				   x);
+
+  /* Subtraction.  */
+  /* 0 <-- (x - x) */
+  assert_binop_folds_to_const (x, MINUS_EXPR, x,
+			       zero);
+  assert_binop_folds_to_nonlvalue (x, MINUS_EXPR, zero,
+				   x);
+
+  /* Multiplication.  */
+  /* 0 <-- (x * 0) */
+  assert_binop_folds_to_const (x, MULT_EXPR, zero,
+			       zero);
+
+  /* (nonlvalue)x <-- (x * 1) */
+  assert_binop_folds_to_nonlvalue (x, MULT_EXPR, one,
+				   x);
+}
+
+}  // anon namespace
+
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 09/15] Add hash-map-tests.c
  2015-11-19 16:46                       ` [PATCH 00/15] Unittests framework v4: -fself-test David Malcolm
                                           ` (4 preceding siblings ...)
  2015-11-19 16:46                         ` [PATCH 05/15] Add selftests to fold-const.c David Malcolm
@ 2015-11-19 16:46                         ` David Malcolm
  2015-11-19 16:46                         ` [PATCH 10/15] Add hash-set-tests.c David Malcolm
                                           ` (9 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-11-19 16:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-hash-map.c):
 https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03301.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files is
> pre-approved.

This version moves the tests to gcc/hash-map-tests.c.

gcc/ChangeLog:
	* hash-map-tests.c: New file.
---
 gcc/hash-map-tests.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)
 create mode 100644 gcc/hash-map-tests.c

diff --git a/gcc/hash-map-tests.c b/gcc/hash-map-tests.c
new file mode 100644
index 0000000..8fc989a
--- /dev/null
+++ b/gcc/hash-map-tests.c
@@ -0,0 +1,81 @@
+/* Unit tests for hash-map.h.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+namespace {
+
+TEST (hash_map_test, map_of_strings_to_int)
+{
+  hash_map <const char *, int> m;
+
+  const char *ostrich = "ostrich";
+  const char *elephant = "elephant";
+  const char *ant = "ant";
+  const char *spider = "spider";
+  const char *millipede = "Illacme plenipes";
+  const char *eric = "half a bee";
+
+  /* A fresh hash_map should be empty.  */
+  EXPECT_EQ (0, m.elements ());
+  EXPECT_EQ (NULL, m.get (ostrich));
+
+  /* Populate the hash_map.  */
+  EXPECT_EQ (false, m.put (ostrich, 2));
+  EXPECT_EQ (false, m.put (elephant, 4));
+  EXPECT_EQ (false, m.put (ant, 6));
+  EXPECT_EQ (false, m.put (spider, 8));
+  EXPECT_EQ (false, m.put (millipede, 750));
+  EXPECT_EQ (false, m.put (eric, 3));
+
+  /* Verify that we can recover the stored values.  */
+  EXPECT_EQ (6, m.elements ());
+  EXPECT_EQ (2, *m.get (ostrich));
+  EXPECT_EQ (4, *m.get (elephant));
+  EXPECT_EQ (6, *m.get (ant));
+  EXPECT_EQ (8, *m.get (spider));
+  EXPECT_EQ (750, *m.get (millipede));
+  EXPECT_EQ (3, *m.get (eric));
+
+  /* Verify removing an item.  */
+  m.remove (eric);
+  EXPECT_EQ (5, m.elements ());
+  EXPECT_EQ (NULL, m.get (eric));
+}
+
+}  /* anon namespace.  */
+
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 02/15] Add selftests to bitmap.c
  2015-11-19 16:46                       ` [PATCH 00/15] Unittests framework v4: -fself-test David Malcolm
                                           ` (2 preceding siblings ...)
  2015-11-19 16:46                         ` [PATCH 08/15] Add selftests to gimple.c David Malcolm
@ 2015-11-19 16:46                         ` David Malcolm
  2015-11-20 10:41                           ` Richard Biener
  2015-11-24 21:13                           ` Jeff Law
  2015-11-19 16:46                         ` [PATCH 05/15] Add selftests to fold-const.c David Malcolm
                                           ` (11 subsequent siblings)
  15 siblings, 2 replies; 176+ messages in thread
From: David Malcolm @ 2015-11-19 16:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff pre-approved the plugin version of this (as a new
file unittests/test-bitmap.c):
  https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03284.html
with:
> OK if/when prereqs are approved.  Minor twiddling if we end up moving it
> elsewhere or standardizing/reducing header files is pre-approved.

This version moves them to bitmap.c

One issue: how to express:
  TEST (bitmap_test, gc_alloc)
in a ChangeLog entry.

I've chosen to write it as (bitmap_test, gc_alloc) since that
has the greatest chance of being found via grep.

gcc/ChangeLog:
	* bitmap.c: Include "selftest.h".
	(bitmap_test, gc_alloc): New selftest.
	(bitmap_test, set_range): New selftest.
	(bitmap_test, clear_bit_in_middle): New selftest.
	(bitmap_test, copying): New selftest.
	(bitmap_test, bitmap_single_bit_set_p): New selftest.
---
 gcc/bitmap.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/gcc/bitmap.c b/gcc/bitmap.c
index f04b8f9..e6f772e 100644
--- a/gcc/bitmap.c
+++ b/gcc/bitmap.c
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "bitmap.h"
+#include "selftest.h"
 
 /* Memory allocation statistics purpose instance.  */
 mem_alloc_description<bitmap_usage> bitmap_mem_desc;
@@ -2094,5 +2095,96 @@ debug (const bitmap_head *ptr)
     fprintf (stderr, "<nil>\n");
 }
 
+#if CHECKING_P
+namespace {
+
+/* Freshly-created bitmaps ought to be empty.  */
+
+TEST (bitmap_test, gc_alloc)
+{
+  bitmap b = bitmap_gc_alloc ();
+  EXPECT_TRUE (bitmap_empty_p (b));
+}
+
+/* Verify bitmap_set_range.  */
+
+TEST (bitmap_test, set_range)
+{
+  bitmap b = bitmap_gc_alloc ();
+  EXPECT_TRUE (bitmap_empty_p (b));
+
+  bitmap_set_range (b, 7, 5);
+  EXPECT_FALSE (bitmap_empty_p (b));
+  EXPECT_EQ (5, bitmap_count_bits (b));
+
+  /* Verify bitmap_bit_p at the boundaries.  */
+  EXPECT_FALSE (bitmap_bit_p (b, 6));
+  EXPECT_TRUE (bitmap_bit_p (b, 7));
+  EXPECT_TRUE (bitmap_bit_p (b, 11));
+  EXPECT_FALSE (bitmap_bit_p (b, 12));
+}
+
+/* Verify splitting a range into two pieces using bitmap_clear_bit.  */
+
+TEST (bitmap_test, clear_bit_in_middle)
+{
+  bitmap b = bitmap_gc_alloc ();
+
+  /* Set b to [100..200].  */
+  bitmap_set_range (b, 100, 100);
+  EXPECT_EQ (100, bitmap_count_bits (b));
+
+  /* Clear a bit in the middle.  */
+  bool changed = bitmap_clear_bit (b, 150);
+  EXPECT_TRUE (changed);
+  EXPECT_EQ (99, bitmap_count_bits (b));
+  EXPECT_TRUE (bitmap_bit_p (b, 149));
+  EXPECT_FALSE (bitmap_bit_p (b, 150));
+  EXPECT_TRUE (bitmap_bit_p (b, 151));
+}
+
+/* Verify bitmap_copy.  */
+
+TEST (bitmap_test, copying)
+{
+  bitmap src = bitmap_gc_alloc ();
+  bitmap_set_range (src, 40, 10);
+
+  bitmap dst = bitmap_gc_alloc ();
+  EXPECT_FALSE (bitmap_equal_p (src, dst));
+  bitmap_copy (dst, src);
+  EXPECT_TRUE (bitmap_equal_p (src, dst));
+
+  /* Verify that we can make them unequal again...  */
+  bitmap_set_range (src, 70, 5);
+  EXPECT_FALSE (bitmap_equal_p (src, dst));
+
+  /* ...and that changing src after the copy didn't affect
+     the other: */
+  EXPECT_FALSE (bitmap_bit_p (dst, 70));
+}
+
+/* Verify bitmap_single_bit_set_p.  */
+TEST (bitmap_test, bitmap_single_bit_set_p)
+{
+  bitmap b = bitmap_gc_alloc ();
+
+  EXPECT_FALSE (bitmap_single_bit_set_p (b));
+
+  bitmap_set_range (b, 42, 1);
+  EXPECT_TRUE (bitmap_single_bit_set_p (b));
+  EXPECT_EQ (42, bitmap_first_set_bit (b));
+
+  bitmap_set_range (b, 1066, 1);
+  EXPECT_FALSE (bitmap_single_bit_set_p (b));
+  EXPECT_EQ (42, bitmap_first_set_bit (b));
+
+  bitmap_clear_range (b, 0, 100);
+  EXPECT_TRUE (bitmap_single_bit_set_p (b));
+  EXPECT_EQ (1066, bitmap_first_set_bit (b));
+}
+
+}  // anon namespace
+#endif /* CHECKING_P */
 
 #include "gt-bitmap.h"
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 14/15] Add selftests to vec.c
  2015-11-19 16:46                       ` [PATCH 00/15] Unittests framework v4: -fself-test David Malcolm
                                           ` (8 preceding siblings ...)
  2015-11-19 16:46                         ` [PATCH 13/15] Add selftests to tree.c David Malcolm
@ 2015-11-19 16:46                         ` David Malcolm
  2015-11-19 16:46                         ` [PATCH 01/15] Selftest framework (unittests v4) David Malcolm
                                           ` (5 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-11-19 16:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-vec.c):
 https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03308.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files is
> pre-approved.

This version puts the tests at the end of vec.c.

gcc/ChangeLog:
	* vec.c: Include "selftest.h".
	(class vec_test): New test subclass.
	(vec_test, quick_push): New selftest.
	(vec_test, safe_push): New selftest.
	(vec_test, truncate): New selftest.
	(vec_test, safe_grow_cleared): New selftest.
	(vec_test, pop): New selftest.
	(vec_test, safe_insert): New selftest.
	(vec_test, ordered_remove): New selftest.
	(vec_test, unordered_remove): New selftest.
	(vec_test, block_remove): New selftest.
	(reverse_cmp): New function.
	(vec_test, qsort): New selftest.
---
 gcc/vec.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 142 insertions(+)

diff --git a/gcc/vec.c b/gcc/vec.c
index 48b10c4..c320635 100644
--- a/gcc/vec.c
+++ b/gcc/vec.c
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "hash-table.h"
+#include "selftest.h"
 
 /* vNULL is an empty type with a template cast operation that returns
    a zero-initialized vec<T, A, L> instance.  Use this when you want
@@ -188,3 +189,144 @@ dump_vec_loc_statistics (void)
 {
   vec_mem_desc.dump (VEC_ORIGIN);
 }
+
+#ifndef GENERATOR_FILE
+#if CHECKING_P
+
+namespace {
+
+class vec_test : public ::selftest::test
+{
+ protected:
+  /* Add the range [START..LIMIT) to V.  */
+  void
+  safe_push_range (vec <int>&v, int start, int limit)
+  {
+    for (int i = start; i < limit; i++)
+      v.safe_push (i);
+  }
+};
+
+TEST_F (vec_test, quick_push)
+{
+  auto_vec <int> v;
+  EXPECT_EQ (0, v.length ());
+  v.reserve (3);
+  EXPECT_EQ (0, v.length ());
+  EXPECT_TRUE (v.space (3));
+  v.quick_push (5);
+  v.quick_push (6);
+  v.quick_push (7);
+  EXPECT_EQ (3, v.length ());
+  EXPECT_EQ (5, v[0]);
+  EXPECT_EQ (6, v[1]);
+  EXPECT_EQ (7, v[2]);
+}
+
+TEST_F (vec_test, safe_push)
+{
+  auto_vec <int> v;
+  EXPECT_EQ (0, v.length ());
+  v.safe_push (5);
+  v.safe_push (6);
+  v.safe_push (7);
+  EXPECT_EQ (3, v.length ());
+  EXPECT_EQ (5, v[0]);
+  EXPECT_EQ (6, v[1]);
+  EXPECT_EQ (7, v[2]);
+}
+
+TEST_F (vec_test, truncate)
+{
+  auto_vec <int> v;
+  EXPECT_EQ (0, v.length ());
+  safe_push_range (v, 0, 10);
+  EXPECT_EQ (10, v.length ());
+
+  v.truncate (5);
+  EXPECT_EQ (5, v.length ());
+}
+
+TEST_F (vec_test, safe_grow_cleared)
+{
+  auto_vec <int> v;
+  EXPECT_EQ (0, v.length ());
+  v.safe_grow_cleared (50);
+  EXPECT_EQ (50, v.length ());
+  EXPECT_EQ (0, v[0]);
+  EXPECT_EQ (0, v[49]);
+}
+
+TEST_F (vec_test, pop)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 5, 20);
+  EXPECT_EQ (15, v.length ());
+
+  int last = v.pop ();
+  EXPECT_EQ (19, last);
+  EXPECT_EQ (14, v.length ());
+}
+
+TEST_F (vec_test, safe_insert)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.safe_insert (5, 42);
+  EXPECT_EQ (4, v[4]);
+  EXPECT_EQ (42, v[5]);
+  EXPECT_EQ (5, v[6]);
+  EXPECT_EQ (11, v.length ());
+}
+
+TEST_F (vec_test, ordered_remove)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.ordered_remove (5);
+  EXPECT_EQ (4, v[4]);
+  EXPECT_EQ (6, v[5]);
+  EXPECT_EQ (9, v.length ());
+}
+
+TEST_F (vec_test, unordered_remove)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.unordered_remove (5);
+  EXPECT_EQ (9, v.length ());
+}
+
+TEST_F (vec_test, block_remove)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.block_remove (5, 3);
+  EXPECT_EQ (3, v[3]);
+  EXPECT_EQ (4, v[4]);
+  EXPECT_EQ (8, v[5]);
+  EXPECT_EQ (9, v[6]);
+  EXPECT_EQ (7, v.length ());
+}
+
+static int reverse_cmp (const void *p_i, const void *p_j)
+{
+  return *(const int *)p_j - *(const int *)p_i;
+}
+
+TEST_F (vec_test, qsort)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.qsort (reverse_cmp);
+  EXPECT_EQ (9, v[0]);
+  EXPECT_EQ (8, v[1]);
+  EXPECT_EQ (1, v[8]);
+  EXPECT_EQ (0, v[9]);
+  EXPECT_EQ (10, v.length ());
+}
+
+}  // anon namespace
+
+#endif /* #if CHECKING_P */
+#endif /* #ifndef GENERATOR_FILE */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 04/15] Add selftests to et-forest.c
  2015-11-19 16:46                       ` [PATCH 00/15] Unittests framework v4: -fself-test David Malcolm
                                           ` (10 preceding siblings ...)
  2015-11-19 16:46                         ` [PATCH 01/15] Selftest framework (unittests v4) David Malcolm
@ 2015-11-19 16:46                         ` David Malcolm
  2015-11-19 16:46                         ` [PATCH 15/15] RFC: Add ggc-tests.c David Malcolm
                                           ` (3 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-11-19 16:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this:
  https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03295.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files
> is pre-approved.

gcc/ChangeLog:
	* et-forest.c: Include "selftest.h".
	(et_forest_test, single_node): New selftest.
	(et_forest_test, simple_tree): New selftest.
---
 gcc/et-forest.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 99 insertions(+)

diff --git a/gcc/et-forest.c b/gcc/et-forest.c
index bf2f765..e4a2a49 100644
--- a/gcc/et-forest.c
+++ b/gcc/et-forest.c
@@ -27,6 +27,7 @@ License along with libiberty; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "alloc-pool.h"
 #include "et-forest.h"
+#include "selftest.h"
 
 /* We do not enable this with CHECKING_P, since it is awfully slow.  */
 #undef DEBUG_ET
@@ -764,3 +765,101 @@ et_root (struct et_node *node)
 
   return r->of;
 }
+
+#if CHECKING_P
+
+namespace {
+
+TEST (et_forest_test, single_node)
+{
+  void *test_data = (void *)0xcafebabe;
+
+  et_node *n = et_new_tree (test_data);
+  EXPECT_EQ (n->data, test_data);
+  EXPECT_EQ (n, et_root (n));
+  et_free_tree (n);
+}
+
+/* Test of this tree:
+       a
+      / \
+     /   \
+    b     c
+   / \    |
+  d   e   f.  */
+
+TEST (et_forest_test, simple_tree)
+{
+  et_node *a = et_new_tree (NULL);
+  et_node *b = et_new_tree (NULL);
+  et_node *c = et_new_tree (NULL);
+  et_node *d = et_new_tree (NULL);
+  et_node *e = et_new_tree (NULL);
+  et_node *f = et_new_tree (NULL);
+
+  et_set_father (b, a);
+  et_set_father (c, a);
+  et_set_father (d, b);
+  et_set_father (e, b);
+  et_set_father (f, c);
+
+  EXPECT_TRUE (et_below (a, a));
+  EXPECT_TRUE (et_below (b, a));
+  EXPECT_TRUE (et_below (c, a));
+  EXPECT_TRUE (et_below (d, a));
+  EXPECT_TRUE (et_below (e, a));
+  EXPECT_TRUE (et_below (f, a));
+
+  EXPECT_FALSE (et_below (a, b));
+  EXPECT_TRUE (et_below (b, b));
+  EXPECT_FALSE (et_below (c, b));
+  EXPECT_TRUE (et_below (d, b));
+  EXPECT_TRUE (et_below (e, b));
+  EXPECT_FALSE (et_below (f, b));
+
+  EXPECT_FALSE (et_below (a, c));
+  EXPECT_FALSE (et_below (b, c));
+  EXPECT_TRUE (et_below (c, c));
+  EXPECT_FALSE (et_below (d, c));
+  EXPECT_FALSE (et_below (e, c));
+  EXPECT_TRUE (et_below (f, c));
+
+  EXPECT_FALSE (et_below (a, d));
+  EXPECT_FALSE (et_below (b, d));
+  EXPECT_FALSE (et_below (c, d));
+  EXPECT_TRUE (et_below (d, d));
+  EXPECT_FALSE (et_below (e, d));
+  EXPECT_FALSE (et_below (f, d));
+
+  EXPECT_FALSE (et_below (a, e));
+  EXPECT_FALSE (et_below (b, e));
+  EXPECT_FALSE (et_below (c, e));
+  EXPECT_FALSE (et_below (d, e));
+  EXPECT_TRUE (et_below (e, e));
+  EXPECT_FALSE (et_below (f, e));
+
+  EXPECT_FALSE (et_below (a, f));
+  EXPECT_FALSE (et_below (b, f));
+  EXPECT_FALSE (et_below (c, f));
+  EXPECT_FALSE (et_below (d, f));
+  EXPECT_FALSE (et_below (e, f));
+  EXPECT_TRUE (et_below (f, f));
+
+  et_free_tree_force (a);
+}
+
+TEST (et_forest_test, disconnected_nodes)
+{
+  et_node *a = et_new_tree (NULL);
+  et_node *b = et_new_tree (NULL);
+
+  EXPECT_FALSE (et_below (a, b));
+  EXPECT_FALSE (et_below (b, a));
+
+  et_free_tree (a);
+  et_free_tree (b);
+}
+
+}  // anon namespace
+
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 07/15] Fix warning in function-tests.c
  2015-11-19 16:46                       ` [PATCH 00/15] Unittests framework v4: -fself-test David Malcolm
@ 2015-11-19 16:46                         ` David Malcolm
  2015-11-19 16:46                         ` [PATCH 03/15] Add selftests to tree-cfg.c David Malcolm
                                           ` (14 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-11-19 16:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Upon porting from gtest.h to selftest.h I ran into this warning which
is fatal during bootstrap:

In file included from ../../../src/gcc/toplev.c:89:0:
../../../src/gcc/function-tests.c: In member function ‘virtual void {anonymous}::function_test_fndecl_int_void::run()’:
../../../src/gcc/selftest.h:182:28: error: comparison with string literal results in unspecified behaviour [-Werror=address]
   if ((EXPECTED) != (ACTUAL))           \
                            ^

../../../src/gcc/function-tests.c:125:3: note: in expansion of macro ‘EXPECT_NE’
   EXPECT_NE ("test_fndecl_int_void", identifier_ptr);
   ^~~~~~~~~

../../../src/gcc/function-tests.c: In member function ‘virtual void {anonymous}::function_test_fndecl_float_intchar::run()’:
../../../src/gcc/selftest.h:182:28: error: comparison with string literal results in unspecified behaviour [-Werror=address]
   if ((EXPECTED) != (ACTUAL))           \
                            ^

../../../src/gcc/function-tests.c:159:3: note: in expansion of macro ‘EXPECT_NE’
   EXPECT_NE ("test_fndecl_float_intchar", identifier_ptr);
   ^~~~~~~~~

This patch fixes the warning.

gcc/ChangeLog:
	* function-tests.c (function_test, fndecl_int_void):
	Introduce local "name" to avoid a "comparison with string literal"
	warning.
	(function_test, fndecl_float_intchar): Likewise.
---
 gcc/function-tests.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/gcc/function-tests.c b/gcc/function-tests.c
index 58b27b8..db105bf 100644
--- a/gcc/function-tests.c
+++ b/gcc/function-tests.c
@@ -111,8 +111,9 @@ class function_test : public ::selftest::test
 TEST_F (function_test, fndecl_int_void)
 {
   auto_vec <tree> param_types;
+  const char *name = "test_fndecl_int_void";
   tree fndecl = make_fndecl (integer_type_node,
-			     "test_fndecl_int_void",
+			     name,
 			     param_types);
   ASSERT_TRUE (fndecl != NULL);
 
@@ -122,7 +123,7 @@ TEST_F (function_test, fndecl_int_void)
   EXPECT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
   /* We expect it to use a *copy* of the string we passed in.  */
   const char *identifier_ptr = IDENTIFIER_POINTER (declname);
-  EXPECT_NE ("test_fndecl_int_void", identifier_ptr);
+  EXPECT_NE (name, identifier_ptr);
   EXPECT_EQ (0, strcmp ("test_fndecl_int_void", identifier_ptr));
 
   /* Verify type of fndecl.  */
@@ -145,8 +146,9 @@ TEST_F (function_test, fndecl_float_intchar)
   auto_vec <tree> param_types;
   param_types.safe_push (integer_type_node);
   param_types.safe_push (char_type_node);
+  const char *name = "test_fndecl_float_intchar";
   tree fndecl = make_fndecl (float_type_node,
-			     "test_fndecl_float_intchar",
+			     name,
 			     param_types);
   ASSERT_TRUE (fndecl != NULL);
 
@@ -156,8 +158,8 @@ TEST_F (function_test, fndecl_float_intchar)
   EXPECT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
   /* We expect it to use a *copy* of the string we passed in.  */
   const char *identifier_ptr = IDENTIFIER_POINTER (declname);
-  EXPECT_NE ("test_fndecl_float_intchar", identifier_ptr);
-  EXPECT_EQ (0, strcmp ("test_fndecl_float_intchar", identifier_ptr));
+  EXPECT_NE (name, identifier_ptr);
+  EXPECT_EQ (0, strcmp (name, identifier_ptr));
 
   /* Verify type of fndecl.  */
   EXPECT_EQ (FUNCTION_DECL, TREE_CODE (fndecl));
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 01/15] Selftest framework (unittests v4)
  2015-11-19 16:46                       ` [PATCH 00/15] Unittests framework v4: -fself-test David Malcolm
                                           ` (9 preceding siblings ...)
  2015-11-19 16:46                         ` [PATCH 14/15] Add selftests to vec.c David Malcolm
@ 2015-11-19 16:46                         ` David Malcolm
  2015-11-19 17:35                           ` Bernd Schmidt
  2015-11-24 22:43                           ` Jeff Law
  2015-11-19 16:46                         ` [PATCH 04/15] Add selftests to et-forest.c David Malcolm
                                           ` (4 subsequent siblings)
  15 siblings, 2 replies; 176+ messages in thread
From: David Malcolm @ 2015-11-19 16:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

This is effectively v4 of the unittests proposal; for the earlier
versions see:
 * v1: https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00765.html
 * v2: https://gcc.gnu.org/ml/gcc-patches/2015-06/msg01224.html
 * v3: https://gcc.gnu.org/ml/gcc-patches/2015-10/msg02947.html

This patch adds a selftest.h/.c to gcc, with an API loosely
modelled on gtest (though without the use of CamelCase): it
supports enough of the gtest API to enable the tests that I
wrote to run with minimal changes.

It adds a -fself-test option, which runs the test at the end
of cc1,cc1plus, etc, similar to how the plugin worked in v2 and v3 of
the kit.

The tests themselves are in the followup patches.
I moved the tests from gcc/testsuite/unittests into gcc.  Where
possible, I moved the tests directly into the end of an
implementation file e.g. gcc/testsuite/unittests/test-vec.c became
an addition to gcc/vec.c; other files don't have a suitable .c file
e.g. for parametrized container types where there's just a .h, so
I created e.g. gcc/hash-map-tests.c

(Irritatingly, touching vec.c means that parts of the selftest code
become needed by e.g. collect2 so that vec.o can link; similarly for
input.o, which gains the location-handling selftests).

Everything apart from the -fself-test option itself is guarded
by #if CHECKING_P, so this all compiles away in a production
build to a "sorry, not supported".

Like gtest, tests are automatically discovered, using
some global object ctor magic.  Sadly this doesn't work
for some reason for source files which are purely tests, so
as a nasty workaround I #include those files from toplev.c

I didn't document -fself-test; should I?  (maybe just in the
internal docs?)

This iteration of the patchkit doesn't yet do anything to
automatically invoke -fself-test; I've been running it by hand
when compiling an empty .c file, so it's been running inside cc1.
How should this be hooked up?

Currently -fself-test requires an input file; should it?  (But if not,
what should the driver run?  All of them?).  Requiring an input file,
and providing an empty one may be simplest.

I anticipate a discussion about output formats; the current output
format is deliberately very verbose, to ensure that we're capturing
everything of interest.  It contains file/line info of each
EXPECT/ASSERT so that it's easy in Emacs to click in the compilation
buffer to go to specific assertions.

NOTE: bitmap_test.bitmap_single_bit_set_p: test starting
../../src/gcc/bitmap.c:2172: PASS: bitmap_test.bitmap_single_bit_set_p: EXPECT_FALSE (bitmap_single_bit_set_p (b))
../../src/gcc/bitmap.c:2175: PASS: bitmap_test.bitmap_single_bit_set_p: EXPECT_TRUE (bitmap_single_bit_set_p (b))
../../src/gcc/bitmap.c:2176: PASS: bitmap_test.bitmap_single_bit_set_p: EXPECT_EQ (42, bitmap_first_set_bit (b))
../../src/gcc/bitmap.c:2179: PASS: bitmap_test.bitmap_single_bit_set_p: EXPECT_FALSE (bitmap_single_bit_set_p (b))
../../src/gcc/bitmap.c:2180: PASS: bitmap_test.bitmap_single_bit_set_p: EXPECT_EQ (42, bitmap_first_set_bit (b))
../../src/gcc/bitmap.c:2183: PASS: bitmap_test.bitmap_single_bit_set_p: EXPECT_TRUE (bitmap_single_bit_set_p (b))
../../src/gcc/bitmap.c:2184: PASS: bitmap_test.bitmap_single_bit_set_p: EXPECT_EQ (1066, bitmap_first_set_bit (b))
NOTE: bitmap_test.bitmap_single_bit_set_p: test ending
NOTE: bitmap_test.clear_bit_in_middle: test starting
../../src/gcc/bitmap.c:2135: PASS: bitmap_test.clear_bit_in_middle: EXPECT_EQ (100, bitmap_count_bits (b))
../../src/gcc/bitmap.c:2139: PASS: bitmap_test.clear_bit_in_middle: EXPECT_TRUE (changed)
[...snip...]
NOTE: 491 pass(es); 0 failure(s)

Potentially we could have some kind of verbosity flag for the
selftests, I guess.

I did attempt to use "inform" to report results, but I don't think
this is appropriate for the most verbose form of output:
(A) some tests manipulate cfun and hence lead to strange
"In function ..." messages as they run based on the changes to cfun
(B) I want to write selftests for the diagnostics subsystem itself

I've successfully bootstrapped&regrtested the combination
of these patches on x86_64-pc-linux-gnu and manually
verified -fself-test (with the exception of the final
patch "RFC: Add ggc-tests.c" which has some issues, as noted
in that patch).

How does this look?

Notes on porting tests from gtest:
* Fixtures inherit from ::selftest::test, rather than
  from gtest's ::testing::Test
* There's no support yet for Setup and Teardown vfuncs (which
  presumably would be "setup" and "teardown")
* I only implemented what I needed
* I didn't implement type-parametrized testing, so for now
  I've dropped test-wide-int.c (which is the only test I had
  that was parametrized over multiple types).

gcc/ChangeLog:
	* Makefile.in (OBJS-libcommon): Add selftest.o.
	(OBJS-libcommon-target): Add selftest.o.
	(COLLECT2_OBJS): Add selftest.o.
	* common.opt (fself-test): New.
	* selftest.c: New file.
	* selftest.h: New file.
	* toplev.c: Include selftest.h.  Add includes of function-tests.c,
	hash-map-tests.c, hash-set-tests.c, rtl-tests.c as a workaround
	for a linker issue.
	(toplev::run_self_tests): New.
	(toplev::main): Handle -fself-test.
	* toplev.h (toplev::run_self_tests): New.
---
 gcc/Makefile.in |   7 +-
 gcc/common.opt  |   4 +
 gcc/selftest.c  | 152 +++++++++++++++++++++++++++++++
 gcc/selftest.h  | 270 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/toplev.c    |  51 +++++++++++
 gcc/toplev.h    |   2 +
 6 files changed, 483 insertions(+), 3 deletions(-)
 create mode 100644 gcc/selftest.c
 create mode 100644 gcc/selftest.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 0fd8d99..ebc9dee 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1532,13 +1532,14 @@ OBJS = \
 # no target dependencies.
 OBJS-libcommon = diagnostic.o diagnostic-color.o diagnostic-show-locus.o \
 	pretty-print.o intl.o \
-	vec.o input.o version.o hash-table.o ggc-none.o memory-block.o
+	vec.o input.o version.o hash-table.o ggc-none.o memory-block.o \
+	selftest.o
 
 # Objects in libcommon-target.a, used by drivers and by the core
 # compiler and containing target-dependent code.
 OBJS-libcommon-target = $(common_out_object_file) prefix.o params.o \
 	opts.o opts-common.o options.o vec.o hooks.o common/common-targhooks.o \
-	hash-table.o file-find.o
+	hash-table.o file-find.o selftest.o
 
 # This lists all host objects for the front ends.
 ALL_HOST_FRONTEND_OBJS = $(foreach v,$(CONFIG_LANGUAGES),$($(v)_OBJS))
@@ -1975,7 +1976,7 @@ gcc-nm.c: gcc-ar.c
 	cp $^ $@
 
 COLLECT2_OBJS = collect2.o collect2-aix.o tlink.o vec.o ggc-none.o \
-  collect-utils.o file-find.o hash-table.o
+  collect-utils.o file-find.o hash-table.o selftest.o
 COLLECT2_LIBS = @COLLECT2_LIBS@
 collect2$(exeext): $(COLLECT2_OBJS) $(LIBDEPS)
 # Don't try modifying collect2 (aka ld) in place--it might be linking this.
diff --git a/gcc/common.opt b/gcc/common.opt
index 3eb520e..2ca7ac2 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2002,6 +2002,10 @@ fselective-scheduling2
 Common Report Var(flag_selective_scheduling2) Optimization
 Run selective scheduling after reload.
 
+fself-test
+Common Var(flag_self_test)
+Run self-tests.
+
 fsel-sched-pipelining
 Common Report Var(flag_sel_sched_pipelining) Init(0) Optimization
 Perform software pipelining of inner loops during selective scheduling.
diff --git a/gcc/selftest.c b/gcc/selftest.c
new file mode 100644
index 0000000..e504c33
--- /dev/null
+++ b/gcc/selftest.c
@@ -0,0 +1,152 @@
+/* A self-testing framework, for use by -fself-test.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+using namespace selftest;
+
+/* Helper function for ::selftest::run_all_tests.  */
+
+static int
+test_comparator (const void *p1, const void *p2)
+{
+  const test *t1 = *static_cast<const test * const *> (p1);
+  const test *t2 = *static_cast<const test * const *> (p2);
+  return strcmp (t1->get_name (), t2->get_name ());
+}
+
+/* Locate and run all tests.
+   Return the number of failures that occurred.  */
+
+int
+selftest::run_all_tests ()
+{
+  /* Create all the tests, in an arbitrary order (based on
+     the order of construction of the global "registrator" instances).  */
+  runner r;
+  auto_vec<test *> tests;
+  for (registrator *iter = registrator::get_first ();
+       iter;
+       iter = iter->get_next ())
+    {
+      test *t = iter->make (&r);
+      tests.safe_push (t);
+    }
+
+  /* Sort the tests into a predictable order.  */
+  tests.qsort (test_comparator);
+
+  /* Run all the tests, in order.  */
+  unsigned i;
+  test *t;
+  FOR_EACH_VEC_ELT (tests, i, t)
+    {
+      r.begin_test (t);
+      t->run ();
+      r.end_test (t);
+    }
+
+  /* Cleanup.  */
+  FOR_EACH_VEC_ELT (tests, i, t)
+    delete t;
+
+  return r.get_num_failures ();
+}
+
+/* Implementation of class ::selftest::runner.  */
+
+/* ::selftest::runner's constructor.  */
+
+runner::runner ()
+: m_passes (0),
+  m_failures (0)
+{
+}
+
+/* ::selftest::runner's destructor.  */
+
+runner::~runner ()
+{
+  fprintf (stderr, "NOTE: %i pass(es); %i failure(s)\n",
+	   m_passes, m_failures);
+}
+
+/* Notify the user that a particular test is about to be run.  */
+
+void
+runner::begin_test (test *t)
+{
+  fprintf (stderr, "NOTE: %s: test starting\n", t->get_name ());
+}
+
+/* Record and report the successful outcome of some aspect of a test.  */
+
+void
+runner::pass (const char *file, int line, test *t, const char *msg)
+{
+  fprintf (stderr, "%s:%i: PASS: %s: %s\n", file, line, t->get_name (), msg);
+  m_passes++;
+}
+
+/* Record and report the failed outcome of some aspect of a test.  */
+
+void
+runner::fail (const char *file, int line, test *t, const char *msg)
+{
+  fprintf (stderr, "%s:%i: FAIL: %s: %s\n", file, line, t->get_name (), msg);
+  m_failures++;
+}
+
+/* Notify the user that a particular test has finished running.  */
+
+void
+runner:: end_test (test *t)
+{
+  fprintf (stderr, "NOTE: %s: test ending\n", t->get_name ());
+}
+
+/* Implementation of class ::selftest::registrator.  */
+
+/* This constructor is run before main; to avoid relying on
+   anything, it simply builds a singly-linked list of
+   instances.  */
+
+registrator::registrator (registrator::callback cb)
+: m_cb (cb), m_next (NULL)
+{
+  if (first)
+    {
+      /* Add this to the front of the list.  */
+      m_next = first;
+      first = this;
+    }
+  else
+    first = this;
+}
+
+/* The singleton head of the registrator linked list.  */
+
+registrator *registrator::first;
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest.h b/gcc/selftest.h
new file mode 100644
index 0000000..2fe738d
--- /dev/null
+++ b/gcc/selftest.h
@@ -0,0 +1,270 @@
+/* A self-testing framework, for use by -fself-test.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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/>.  */
+
+#ifndef GCC_SELFTEST_H
+#define GCC_SELFTEST_H
+
+/* The selftest code should entirely disappear in a production
+   configuration, hence we guard all of it with #if CHECKING_P.  */
+
+#if CHECKING_P
+
+namespace selftest {
+
+class test;
+class runner;
+class registrator;
+
+/* The entrypoint for running all tests.  */
+
+extern int run_all_tests ();
+
+/* The class ::selftest::runner is responsible for gathering results,
+   and for output.  */
+
+class runner
+{
+public:
+  runner ();
+  ~runner ();
+
+  void begin_test (test *t);
+  void pass (const char *file, int line, test *t, const char *msg);
+  void fail (const char *file, int line, test *t, const char *msg);
+  void end_test (test *t);
+
+  int get_num_failures () const { return m_failures; }
+
+private:
+  int m_passes;
+  int m_failures;
+};
+
+/* The class ::selftest::test is a base class from which specific
+   tests inherit, via the TEST and TEST_F macros below.  */
+
+class test
+{
+ public:
+  virtual ~test () {}
+  virtual void run () = 0;
+
+  const char *get_name () const { return m_name; }
+
+  void set_name (const char *name) { m_name = name; }
+  void set_runner (runner *r) { m_runner = r; }
+
+ protected:
+  void pass (const char *file, int line, const char *msg)
+  {
+    m_runner->pass (file, line, this, msg);
+  }
+  void fail (const char *file, int line, const char *msg)
+  {
+    m_runner->fail (file, line, this, msg);
+  }
+
+  /* We don't yet implement setup & teardown hooks.  */
+
+ private:
+  const char *m_name;
+  runner *m_runner;
+};
+
+/* An implementation detail of automatic test registration.
+   Global instances are created via the REGISTER_TEST below.
+   The constructor runs before main, wiring them up into a
+   singly-linked list, which can be traversed by
+   ::selftest::run_all_tests.  */
+
+class registrator
+{
+ public:
+  typedef test *(*callback) (runner *r);
+  registrator (callback cb);
+
+  static registrator *get_first () { return first; }
+  registrator *get_next () const { return m_next; }
+
+  test *make (runner *r) const { return m_cb (r); }
+
+ private:
+  callback m_cb;
+  registrator *m_next;
+  static registrator *first;
+};
+
+} /* end of namespace selftest.  */
+
+/* Macros for creating test functions.  */
+
+/* Define a new test, expecting a braced function body to follow.
+   The function body becomes the implementation of a "run" method of
+   a new ::selftest::test subclass, which will be instantiated and run
+   by RUN_ALL_TESTS.  */
+
+#define TEST(TEST_CASE_NAME, TEST_NAME)				\
+  IMPL_TEST_SUBCLASS (TEST_CASE_NAME ## _ ## TEST_NAME,		\
+		      ::selftest::test,				\
+		      (#TEST_CASE_NAME "." #TEST_NAME) )
+
+
+/* As per TEST above, but inheriting from a fixture subclass, rather
+   than directly from ::selftest::test.  */
+
+#define TEST_F(FIXTURE_CLASS_NAME, TEST_NAME)		    \
+  IMPL_TEST_SUBCLASS (FIXTURE_CLASS_NAME ## _ ## TEST_NAME, \
+		      FIXTURE_CLASS_NAME,		    \
+		      (#FIXTURE_CLASS_NAME "." #TEST_NAME) )
+
+/* Macros for writing tests.  */
+
+/* Evaluate EXPR and coerce to bool, issuing PASS if it is true,
+   FAIL if it false.  */
+
+#define EXPECT_TRUE(EXPR)				\
+  SELFTEST_BEGIN_STMT					\
+  const char *desc = "EXPECT_TRUE (" #EXPR ")";	\
+  bool actual = (EXPR);				\
+  if (actual)						\
+    pass (__FILE__, __LINE__, desc);			\
+  else							\
+    fail (__FILE__, __LINE__, desc);			\
+  SELFTEST_END_STMT
+
+/* Evaluate EXPR and coerce to bool, issuing PASS if it is false,
+   FAIL if it true.  */
+
+#define EXPECT_FALSE(EXPR)					\
+  SELFTEST_BEGIN_STMT						\
+  const char *desc = "EXPECT_FALSE (" #EXPR ")";		\
+  bool actual = (EXPR);					\
+  if (actual)							\
+    fail (__FILE__, __LINE__, desc);				\
+  else								\
+    pass (__FILE__, __LINE__, desc);				\
+  SELFTEST_END_STMT
+
+/* Evaluate EXPECTED and ACTUAL and compare them with ==, issuing PASS
+   if they are equal, FAIL if they are non-equal.  */
+
+#define EXPECT_EQ(EXPECTED, ACTUAL)			       \
+  SELFTEST_BEGIN_STMT					       \
+  const char *desc = "EXPECT_EQ (" #EXPECTED ", " #ACTUAL ")"; \
+  if ((EXPECTED) == (ACTUAL))				       \
+    pass (__FILE__, __LINE__, desc);			       \
+  else							       \
+    fail (__FILE__, __LINE__, desc);			       \
+  SELFTEST_END_STMT
+
+/* Evaluate EXPECTED and ACTUAL and compare them with !=, issuing PASS
+   if they are non-equal, FAIL if they are equal.  */
+
+#define EXPECT_NE(EXPECTED, ACTUAL)			       \
+  SELFTEST_BEGIN_STMT					       \
+  const char *desc = "EXPECT_NE (" #EXPECTED ", " #ACTUAL ")"; \
+  if ((EXPECTED) != (ACTUAL))				       \
+    pass (__FILE__, __LINE__, desc);			       \
+  else							       \
+    fail (__FILE__, __LINE__, desc);			       \
+  SELFTEST_END_STMT
+
+/* Evaluate EXPECTED and ACTUAL and compare them with strcmp, issuing
+   PASS if they are equal, FAIL if they are non-equal.  */
+
+#define EXPECT_STREQ(EXPECTED, ACTUAL)			       \
+  SELFTEST_BEGIN_STMT					       \
+  const char *desc = "EXPECT_STREQ (" #EXPECTED ", " #ACTUAL ")"; \
+  const char *expected_ = (EXPECTED);				  \
+  const char *actual_ = (ACTUAL);				  \
+  if (0 == strcmp (expected_, actual_))				  \
+    pass (__FILE__, __LINE__, desc);			       \
+  else							       \
+    fail (__FILE__, __LINE__, desc);			       \
+  SELFTEST_END_STMT
+
+/* Evaluate PRED1 (VAL1), issuing PASS if it is true, FAIL if
+   it false.  */
+
+#define EXPECT_PRED1(PRED1, VAL1)			\
+  SELFTEST_BEGIN_STMT					\
+  const char *desc = "EXPECT_PRED1 (" #PRED1 ", " #VAL1 ")";	\
+  bool actual = (PRED1) (VAL1);				\
+  if (actual)						\
+    pass (__FILE__, __LINE__, desc);			\
+  else							\
+    fail (__FILE__, __LINE__, desc);			\
+  SELFTEST_END_STMT
+
+/* As per EXPECT_TRUE, but immediately end the test (via return) if
+   if fails.  */
+
+#define ASSERT_TRUE(EXPR)				\
+  SELFTEST_BEGIN_STMT					\
+  const char *desc = "ASSERT_TRUE (" #EXPR ")";	\
+  bool actual = (EXPR);				\
+  if (actual)						\
+    pass (__FILE__, __LINE__, desc);			\
+  else							\
+    {							\
+      fail (__FILE__, __LINE__, desc);			\
+      return;						\
+    }							\
+  SELFTEST_END_STMT
+
+ /* A macro for running all tests, returning the number of failures.  */
+
+#define RUN_ALL_TESTS() \
+  ::selftest::run_all_tests ()
+
+
+/* The remaining macros are implementation details, for internal use.  */
+
+/* A macro for registering a test subclass, by creating a global object
+   with a non-trivial ctor.  */
+
+#define REGISTER_TEST(SUBCLASSNAME) \
+  static selftest::registrator registrator_for_ ##SUBCLASSNAME(&SUBCLASSNAME::make)
+
+/* This macro is used to implement TEST and TEST_F.  It creates a new
+   subclass of ::selftest::test, and begins the definition of a "run"
+   method for the subclass, expecting a braced method body to follow.  */
+
+#define IMPL_TEST_SUBCLASS(SUBCLASS_NAME, BASE_CLASS, NAME)		\
+  class SUBCLASS_NAME : public BASE_CLASS				\
+  {									\
+  public:								\
+    void run ();							\
+    static test *make (::selftest::runner *r)				\
+    {									\
+      test *t = new SUBCLASS_NAME ();					\
+      t->set_name (NAME);						\
+      t->set_runner (r);						\
+      return t;							\
+    }									\
+  };									\
+  REGISTER_TEST(SUBCLASS_NAME);					\
+  void SUBCLASS_NAME::run ()
+
+#define SELFTEST_BEGIN_STMT do {
+#define SELFTEST_END_STMT   } while (0)
+
+#endif /* #if CHECKING_P */
+
+#endif /* GCC_SELFTEST_H */
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 5aade2f..1089ca9 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -86,6 +86,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "xcoffout.h"		/* Needed for external data declarations. */
 #endif
 
+#include "selftest.h"
+
 #include <new>
 
 static void general_init (const char *, bool);
@@ -1995,6 +1997,52 @@ toplev::start_timevars ()
   timevar_start (TV_TOTAL);
 }
 
+/* For some tests, there's a natural source file to place them in.
+   For others, they can live in their own "foo-tests.c" file.
+   Ideally, these "foo-tests.c" files would be added to OBJS in
+   Makefile.in.  However, for some reason that approach doesn't
+   work: the tests don't get run..  The linker appears to be discarding
+   the global "registrator" instances in files which are purely
+   test cases (apart from ggc-tests.c, which works for some
+   reason; perhaps the GC roots is poking the linker in such a way
+   as to prevent the issue).
+
+   Hence as a workaround, we instead directly include the files here.  */
+
+#if CHECKING_P
+
+#include "function-tests.c"
+#include "hash-map-tests.c"
+#include "hash-set-tests.c"
+#include "rtl-tests.c"
+
+#endif /* #if CHECKING_P */
+
+/* Handle -fself-test.   */
+
+void
+toplev::run_self_tests ()
+{
+#if CHECKING_P
+  /* Reset some state.  */
+  input_location = UNKNOWN_LOCATION;
+  bitmap_obstack_initialize (NULL);
+
+  /* Run the tests.  */
+  int result = RUN_ALL_TESTS();
+
+  /* Ensure that a test failure leads to the process exiting with
+     a non-zero exit code.  */
+  if (result)
+    error ("at least one test failure occurred");
+
+  /* Cleanup.  */
+  bitmap_obstack_release (NULL);
+#else
+  sorry ("self-tests are not enabled in this build");
+#endif /* #if CHECKING_P */
+}
+
 /* Entry point of cc1, cc1plus, jc1, f771, etc.
    Exit code is FATAL_EXIT_CODE if can't open files or if there were
    any errors, or SUCCESS_EXIT_CODE if compilation succeeded.
@@ -2061,6 +2109,9 @@ toplev::main (int argc, char **argv)
   if (warningcount || errorcount || werrorcount)
     print_ignored_options ();
 
+  if (flag_self_test)
+    run_self_tests ();
+
   /* Invoke registered plugin callbacks if any.  Some plugins could
      emit some diagnostics here.  */
   invoke_plugin_callbacks (PLUGIN_FINISH, NULL);
diff --git a/gcc/toplev.h b/gcc/toplev.h
index e613fec..776d763 100644
--- a/gcc/toplev.h
+++ b/gcc/toplev.h
@@ -42,6 +42,8 @@ private:
 
   void start_timevars ();
 
+  void run_self_tests ();
+
   bool m_use_TV_TOTAL;
   bool m_init_signals;
 };
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 13/15] Add selftests to tree.c
  2015-11-19 16:46                       ` [PATCH 00/15] Unittests framework v4: -fself-test David Malcolm
                                           ` (7 preceding siblings ...)
  2015-11-19 16:46                         ` [PATCH 06/15] Add function-tests.c David Malcolm
@ 2015-11-19 16:46                         ` David Malcolm
  2015-11-19 16:46                         ` [PATCH 14/15] Add selftests to vec.c David Malcolm
                                           ` (6 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-11-19 16:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-tree.c):
 https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03303.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files is
> pre-approved.

This version puts the tests at the end of tree.c.

gcc/ChangeLog:
	* tree.c: Include "selftest.h".
	(tree_test, integer_constants): New selftest.
	(tree_test, identifiers): New selftest.
	(tree_test, labels): New selftest.
---
 gcc/tree.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/gcc/tree.c b/gcc/tree.c
index d5a71a3..6ed1914 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -61,6 +61,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "print-tree.h"
 #include "ipa-utils.h"
+#include "selftest.h"
 
 /* Tree code classes.  */
 
@@ -13951,4 +13952,50 @@ combined_fn_name (combined_fn fn)
     return internal_fn_name (as_internal_fn (fn));
 }
 
+#if CHECKING_P
+
+namespace {
+
+/* Verify that integer constants are sane.  */
+
+TEST (tree_test, integer_constants)
+{
+  ASSERT_TRUE (integer_type_node != NULL);
+  EXPECT_TRUE (build_int_cst (integer_type_node, 0) != NULL);
+
+  tree type = integer_type_node;
+
+  tree zero = build_zero_cst (type);
+  EXPECT_EQ (INTEGER_CST, TREE_CODE (zero));
+  EXPECT_EQ (type, TREE_TYPE (zero));
+
+  tree one = build_int_cst (type, 1);
+  EXPECT_EQ (INTEGER_CST, TREE_CODE (one));
+  EXPECT_EQ (type, TREE_TYPE (zero));
+}
+
+/* Verify identifiers.  */
+
+TEST (tree_test, identifiers)
+{
+  tree identifier = get_identifier ("foo");
+  EXPECT_EQ (3, IDENTIFIER_LENGTH (identifier));
+  EXPECT_STREQ ("foo", IDENTIFIER_POINTER (identifier));
+}
+
+/* Verify LABEL_DECL.  */
+
+TEST (tree_test, labels)
+{
+  tree identifier = get_identifier ("err");
+  tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
+				identifier, void_type_node);
+  EXPECT_EQ (-1, LABEL_DECL_UID (label_decl));
+  EXPECT_FALSE (FORCED_LABEL (label_decl));
+}
+
+}  // anon namespace
+
+#endif /* CHECKING_P */
+
 #include "gt-tree.h"
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 10/15] Add hash-set-tests.c
  2015-11-19 16:46                       ` [PATCH 00/15] Unittests framework v4: -fself-test David Malcolm
                                           ` (5 preceding siblings ...)
  2015-11-19 16:46                         ` [PATCH 09/15] Add hash-map-tests.c David Malcolm
@ 2015-11-19 16:46                         ` David Malcolm
  2015-11-19 16:46                         ` [PATCH 06/15] Add function-tests.c David Malcolm
                                           ` (8 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-11-19 16:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-hash-set.c):
 https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03300.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files is
> pre-approved.

This version moves the tests to gcc/hash-set-tests.c.

gcc/ChangeLog:
	* hash-set-tests.c: New file.
---
 gcc/hash-set-tests.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 gcc/hash-set-tests.c

diff --git a/gcc/hash-set-tests.c b/gcc/hash-set-tests.c
new file mode 100644
index 0000000..8582663
--- /dev/null
+++ b/gcc/hash-set-tests.c
@@ -0,0 +1,57 @@
+/* Unit tests for hash-set.h.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+namespace {
+
+TEST (hash_set_test, set_of_strings)
+{
+  hash_set <const char *> s;
+  EXPECT_EQ (0, s.elements ());
+
+  const char *red = "red";
+  const char *green = "green";
+  const char *blue = "blue";
+
+  EXPECT_EQ (false, s.contains (red));
+
+  /* Populate the hash_set.  */
+  EXPECT_EQ (false, s.add (red));
+  EXPECT_EQ (false, s.add (green));
+  EXPECT_EQ (false, s.add (blue));
+
+  /* Verify that the values are now within the set.  */
+  EXPECT_EQ (true, s.contains (red));
+  EXPECT_EQ (true, s.contains (green));
+  EXPECT_EQ (true, s.contains (blue));
+}
+
+}  /* anon namespace.  */
+
+#endif /* #if CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 12/15] Add rtl-tests.c
  2015-11-19 16:46                       ` [PATCH 00/15] Unittests framework v4: -fself-test David Malcolm
                                           ` (12 preceding siblings ...)
  2015-11-19 16:46                         ` [PATCH 15/15] RFC: Add ggc-tests.c David Malcolm
@ 2015-11-19 17:03                         ` David Malcolm
  2015-11-19 17:03                         ` [PATCH 11/15] Add selftests to input.c David Malcolm
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-11-19 17:03 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-rtl.c):
 https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03302.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files is
>pre-approved.

This version puts the tests in gcc/rtl-tests.c.

gcc/ChangeLog:
	* rtl-tests.c: New file.
---
 gcc/rtl-tests.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 98 insertions(+)
 create mode 100644 gcc/rtl-tests.c

diff --git a/gcc/rtl-tests.c b/gcc/rtl-tests.c
new file mode 100644
index 0000000..611d82a
--- /dev/null
+++ b/gcc/rtl-tests.c
@@ -0,0 +1,98 @@
+/* Unit tests for RTL-handling.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "pretty-print.h"
+#include "cfgbuild.h"
+#include "print-rtl.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+namespace {
+
+class rtl_test : public ::selftest::test
+{
+ protected:
+  void
+  verify_print_pattern (const char *expected, rtx pat)
+  {
+    pretty_printer pp;
+    print_pattern (&pp, pat, 1);
+    EXPECT_STREQ (expected, pp_formatted_text (&pp));
+  }
+};
+
+/* Unit testing of "single_set".  */
+TEST_F (rtl_test, test_single_set)
+{
+  /* A label is not a SET.  */
+  EXPECT_EQ (NULL_RTX, single_set (gen_label_rtx ()));
+
+  /* An unconditional jump insn is a single SET.  */
+  rtx set_pc = gen_rtx_SET (pc_rtx,
+			    gen_rtx_LABEL_REF (VOIDmode,
+					       gen_label_rtx ()));
+  rtx_insn *jump_insn = emit_jump_insn (set_pc);
+  EXPECT_EQ (set_pc, single_set (jump_insn));
+
+  /* etc */
+}
+
+TEST_F (rtl_test, uncond_jump)
+{
+  rtx_insn *label = gen_label_rtx ();
+  rtx jump_pat = gen_rtx_SET (pc_rtx,
+			      gen_rtx_LABEL_REF (VOIDmode,
+						 label));
+  EXPECT_EQ (SET, jump_pat->code);
+  EXPECT_EQ (LABEL_REF, SET_SRC (jump_pat)->code);
+  EXPECT_EQ (label, LABEL_REF_LABEL (SET_SRC (jump_pat)));
+  EXPECT_EQ (PC, SET_DEST (jump_pat)->code);
+
+  verify_print_pattern ("pc=L0", jump_pat);
+
+  rtx_insn *jump_insn = emit_jump_insn (jump_pat);
+  EXPECT_FALSE (any_condjump_p (jump_insn));
+  EXPECT_TRUE (any_uncondjump_p (jump_insn));
+  EXPECT_TRUE (pc_set (jump_insn));
+  EXPECT_TRUE (simplejump_p (jump_insn));
+  EXPECT_TRUE (onlyjump_p (jump_insn));
+  EXPECT_TRUE (control_flow_insn_p (jump_insn));
+}
+
+}  /* anon namespace.  */
+
+#endif /* #if CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 11/15] Add selftests to input.c
  2015-11-19 16:46                       ` [PATCH 00/15] Unittests framework v4: -fself-test David Malcolm
                                           ` (13 preceding siblings ...)
  2015-11-19 17:03                         ` [PATCH 12/15] Add rtl-tests.c David Malcolm
@ 2015-11-19 17:03                         ` David Malcolm
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-11-19 17:03 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff conditionally approved an earlier version of this (as
unittests/test-locations.c):
  https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03307.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files is
> pre-approved.
>
> Consider removing the stuff we aren't actually using. I think
> there was something simliar in another unittest file I looked at.

This version moves the tests to the end of input.c, and re-enables
the __FILE__ access in location_test.

Doing so requires the selftest to be run from the build directory
so that e.g. cc1 can locate __FILE__.

gcc/ChangeLog:
	* input.c: Include "selftest.h".
	(class location_test): New test subclass.
	(location_test, accessing_ordinary_linemaps): New selftest.
	(location_test, unknown_location): New selftest.
	(location_test, builtins): New selftest.
	(location_test, reading_source_line): New selftest.
---
 gcc/input.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)

diff --git a/gcc/input.c b/gcc/input.c
index ce84f10..b96d6fa 100644
--- a/gcc/input.c
+++ b/gcc/input.c
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "intl.h"
 #include "diagnostic-core.h"
+#include "selftest.h"
 
 /* This is a cache used by get_next_line to store the content of a
    file to be searched for file lines.  */
@@ -1126,3 +1127,109 @@ dump_location_info (FILE *stream)
   dump_labelled_location_range (stream, "AD-HOC LOCATIONS",
 				MAX_SOURCE_LOCATION + 1, UINT_MAX);
 }
+
+#if CHECKING_P
+
+namespace {
+
+/* Fixture for testing location-handling.
+   Creates some pre-canned location_t values.  */
+
+class location_test : public ::selftest::test
+{
+ protected:
+  location_test ()
+  {
+    /* Build a simple linemap describing some locations. */
+    linemap_add (line_table, LC_ENTER, false, "foo.c", 0);
+
+    linemap_line_start (line_table, 1, 100);
+    loc_a = linemap_position_for_column (line_table, 1);
+    loc_b = linemap_position_for_column (line_table, 23);
+
+    linemap_line_start (line_table, 2, 100);
+    loc_c = linemap_position_for_column (line_table, 1);
+    loc_d = linemap_position_for_column (line_table, 17);
+
+    /* Example of a very long line.  */
+    linemap_line_start (line_table, 3, 2000);
+    loc_e = linemap_position_for_column (line_table, 700);
+
+    linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+
+    /* Multiple files.  */
+    linemap_add (line_table, LC_ENTER, false, "bar.c", 0);
+    linemap_line_start (line_table, 1, 200);
+    loc_f = linemap_position_for_column (line_table, 150);
+    linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+  }
+
+  /* Verify the result of LOCATION_FILE/LOCATION_LINE/LOCATION_COLUMN
+     on LOC.  */
+  void
+  expect_loceq (const char *exp_filename,
+		int exp_linenum,
+		int exp_colnum,
+		location_t loc)
+  {
+    EXPECT_STREQ (exp_filename, LOCATION_FILE (loc));
+    EXPECT_EQ (exp_linenum, LOCATION_LINE (loc));
+    EXPECT_EQ (exp_colnum, LOCATION_COLUMN (loc));
+  }
+
+  location_t loc_a;
+  location_t loc_b;
+  location_t loc_c;
+  location_t loc_d;
+  location_t loc_e;
+  location_t loc_f;
+};
+
+/* Verify basic operation of ordinary linemaps.  */
+
+TEST_F (location_test, accessing_ordinary_linemaps)
+{
+  /* Verify that we can recover the location info.  */
+  expect_loceq ("foo.c", 1, 1, loc_a);
+  expect_loceq ("foo.c", 1, 23, loc_b);
+  expect_loceq ("foo.c", 2, 1, loc_c);
+  expect_loceq ("foo.c", 2, 17, loc_d);
+  expect_loceq ("foo.c", 3, 700, loc_e);
+  expect_loceq ("bar.c", 1, 150, loc_f);
+}
+
+TEST_F (location_test, unknown_location)
+{
+  EXPECT_EQ (NULL, LOCATION_FILE (UNKNOWN_LOCATION));
+  EXPECT_EQ (0, LOCATION_LINE (UNKNOWN_LOCATION));
+  EXPECT_EQ (0, LOCATION_COLUMN (UNKNOWN_LOCATION));
+}
+
+TEST_F (location_test, builtins)
+{
+  expect_loceq ("<built-in>", 0, 0, BUILTINS_LOCATION);
+  EXPECT_PRED1 (is_location_from_builtin_token, BUILTINS_LOCATION);
+  EXPECT_FALSE (is_location_from_builtin_token (loc_a));
+}
+
+/* Verify reading of input files (e.g. for caret-based diagnostics.  */
+
+TEST_F (location_test, reading_source_line)
+{
+  /* We will read *this* source file, using __FILE__.
+     Here is some specific text to read and test for:
+     The quick brown fox jumps over the lazy dog.  */
+  const int linenum_after_test_message = __LINE__;
+  const int linenum = linenum_after_test_message - 1;
+
+  int line_size;
+  const char *source_line = location_get_source_line (__FILE__, linenum, &line_size);
+  EXPECT_TRUE (source_line != NULL);
+  EXPECT_STREQ ("     The quick brown fox jumps over the lazy dog.  */",
+		source_line);
+  EXPECT_EQ (53, line_size);
+}
+
+} /* anon namespace. */
+
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 01/15] Selftest framework (unittests v4)
  2015-11-19 16:46                         ` [PATCH 01/15] Selftest framework (unittests v4) David Malcolm
@ 2015-11-19 17:35                           ` Bernd Schmidt
  2015-11-19 18:08                             ` David Malcolm
  2015-11-24 20:29                             ` Jeff Law
  2015-11-24 22:43                           ` Jeff Law
  1 sibling, 2 replies; 176+ messages in thread
From: Bernd Schmidt @ 2015-11-19 17:35 UTC (permalink / raw)
  To: David Malcolm, gcc-patches; +Cc: Jeff Law

In general I'm much happier with this approach, and I think this series 
is close to ready, but I want to bring up some questions that could use 
wider discussion.

> This patch adds a selftest.h/.c to gcc, with an API loosely
> modelled on gtest (though without the use of CamelCase): it
> supports enough of the gtest API to enable the tests that I
> wrote to run with minimal changes.

Here there's a question of style. I don't want to approve or reject this 
just now, I'd like to hear what others think. To my eyes this still 
looks rather seriously overengineered. Plain gcc_assert and if (cond) 
abort (); would work just fine for the tests IMO, it's what we have for 
regular testcases where we don't distinguish between all sorts of 
microscopic subtests, and any gcc_assert failure is easy enough to 
debug, just load up cc1 into the debugger and run. I don't think we need 
output for tests that are really just expected to pass always, all we 
need is the build to stop if an internal error is detected.

If I'd written it I'd also have used a somewhat lower-tech approach for 
the registration and running of tests, but once again I'd like to hear 
from others.

For things like

> +#define RUN_ALL_TESTS() \
> +  ::selftest::run_all_tests ()

I don't see the point of the macro. Also, in [8/15]

> +class gimple_test : public ::selftest::test
> +{
> + protected:
> +  void
> +  verify_gimple_pp (const char *expected, gimple *stmt)
> +  {
> +    pretty_printer pp;
> +    pp_gimple_stmt_1 (&pp, stmt, 0 /* spc */, 0 /* flags */);
> +    EXPECT_STREQ (expected, pp_formatted_text (&pp));
> +  }
> +};
> +

Why have the class rather than just a function? This sort of thing makes 
me go "overuse of C++".


Bernd

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 01/15] Selftest framework (unittests v4)
  2015-11-19 17:35                           ` Bernd Schmidt
@ 2015-11-19 18:08                             ` David Malcolm
  2015-11-19 18:15                               ` Mike Stump
  2015-11-19 18:44                               ` Bernd Schmidt
  2015-11-24 20:29                             ` Jeff Law
  1 sibling, 2 replies; 176+ messages in thread
From: David Malcolm @ 2015-11-19 18:08 UTC (permalink / raw)
  To: Bernd Schmidt; +Cc: gcc-patches, Jeff Law

On Thu, 2015-11-19 at 18:35 +0100, Bernd Schmidt wrote:
> In general I'm much happier with this approach, and I think this series 
> is close to ready, but I want to bring up some questions that could use 
> wider discussion.

> > This patch adds a selftest.h/.c to gcc, with an API loosely
> > modelled on gtest (though without the use of CamelCase): it
> > supports enough of the gtest API to enable the tests that I
> > wrote to run with minimal changes.
> 
> Here there's a question of style. I don't want to approve or reject this 
> just now, I'd like to hear what others think. To my eyes this still 
> looks rather seriously overengineered. Plain gcc_assert and if (cond) 
> abort (); would work just fine for the tests IMO, it's what we have for 
> regular testcases where we don't distinguish between all sorts of 
> microscopic subtests, and any gcc_assert failure is easy enough to 
> debug, just load up cc1 into the debugger and run. I don't think we need 
> output for tests that are really just expected to pass always, all we 
> need is the build to stop if an internal error is detected.

gcc_assert terminates the process and no further testing is done,
whereas the approach the kit tries to run as much of the testsuite as
possible, and then fail if any errors occurred.

Given that the aim is for something that runs very quickly in stage1 and
should rarely fail, this distinction may be irrelevant, though maybe the
latter approach is better for the case where *something* has broken a
lot of tests and you want to see what the lowest level failures are,
rather than just the first one that broke.

Consider the case of something being tested on, say x86_64, that works
fine there, but which breaks some of the selftests on AIX (perhaps the
selftest failure is indicating a genuine problem, or perhaps the
selftest is over-specified).  I believe it would be preferable to have
some sort of report on the scope of the breakage, rather than require
each test to be fixed before the self-test can continue.

> If I'd written it I'd also have used a somewhat lower-tech approach for 
> the registration and running of tests, but once again I'd like to hear 
> from others.

The patch kit does use a lot of "magic" via macros and C++.

Taking registration/discovery/running in completely the other direction,
another approach could be a completely manual approach, with something
like this in toplev.c:

  bitmap_selftest ();
  et_forest_selftest ();
  /* etc */
  vec_selftest ();

This has the advantage of being explicit, and the disadvantage of
requiring a bit more typing.  I was going to add that there might be
more risk of adding a test and not having it called, but I suspect that
the "function declared but not used" warning would protect us from that.
(there's also the loss of the ability to e.g. randomize the order in
which the tests get run, but that's less important).

(possibly passing in a "selftest *" param if we're doing the
try-to-run-everything approach, so we can count failures etc without
introducing globals)

Was that what you had in mind, or something else?

> For things like
> 
> > +#define RUN_ALL_TESTS() \
> > +  ::selftest::run_all_tests ()
> 
> I don't see the point of the macro. 

FWIW, this was for compatibility with the gtest API, but yeah, it's
redundant.

>Also, in [8/15]
> 
> > +class gimple_test : public ::selftest::test
> > +{
> > + protected:
> > +  void
> > +  verify_gimple_pp (const char *expected, gimple *stmt)
> > +  {
> > +    pretty_printer pp;
> > +    pp_gimple_stmt_1 (&pp, stmt, 0 /* spc */, 0 /* flags */);
> > +    EXPECT_STREQ (expected, pp_formatted_text (&pp));
> > +  }
> > +};
> > +
> 
> Why have the class rather than just a function? This sort of thing makes 
> me go "overuse of C++".

It's useful if a test has state: the test functions are methods of a
class, so the state can live as instance data, and hence the helper
functions in the fixtures can get at it.  But this could be achieved in
other ways that might be more explicit, and use less macro chicanery.
(also, the result reporting relies on the test code being a method of
a ::selftest::test subclass so it's useful to write fixtures as
subclasses to inherit from, but yeah, this could be overengineering it).


Thanks
Dave

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 01/15] Selftest framework (unittests v4)
  2015-11-19 18:08                             ` David Malcolm
@ 2015-11-19 18:15                               ` Mike Stump
  2015-11-19 18:44                               ` Bernd Schmidt
  1 sibling, 0 replies; 176+ messages in thread
From: Mike Stump @ 2015-11-19 18:15 UTC (permalink / raw)
  To: David Malcolm; +Cc: Bernd Schmidt, gcc-patches, Jeff Law

On Nov 19, 2015, at 10:08 AM, David Malcolm <dmalcolm@redhat.com> wrote:
> gcc_assert terminates the process and no further testing is done,
> whereas the approach the kit tries to run as much of the testsuite as
> possible, and then fail if any errors occurred.

Running as much as possible is desirable over stopping at the first failure.  I personally like the magic registration.  Not sure if we need the qsort (they can be run in registration order I think).

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 01/15] Selftest framework (unittests v4)
  2015-11-19 18:08                             ` David Malcolm
  2015-11-19 18:15                               ` Mike Stump
@ 2015-11-19 18:44                               ` Bernd Schmidt
  2015-11-19 20:04                                 ` Mikhail Maltsev
                                                   ` (2 more replies)
  1 sibling, 3 replies; 176+ messages in thread
From: Bernd Schmidt @ 2015-11-19 18:44 UTC (permalink / raw)
  To: David Malcolm; +Cc: gcc-patches, Jeff Law

On 11/19/2015 07:08 PM, David Malcolm wrote:
> gcc_assert terminates the process and no further testing is done,
> whereas the approach the kit tries to run as much of the testsuite as
> possible, and then fail if any errors occurred.

Yeah, but let's say someone is working on bitmaps and one of the bitmap 
tests fail, it's somewhat unlikely that cfg will also fail (or if it 
does, it'll be a consequence of the earlier failure). You debug the 
issue, fix it, and run cc1 -fself-test again to see if that sorted it out.

As I said, it's a matter of taste and style and I won't claim that my 
way is necessarily the right one, but I do want to see if others feel 
the same.

> The patch kit does use a lot of "magic" via macros and C++.
>
> Taking registration/discovery/running in completely the other direction,
> another approach could be a completely manual approach, with something
> like this in toplev.c:
>
>    bitmap_selftest ();
>    et_forest_selftest ();
>    /* etc */
>    vec_selftest ();
>
> This has the advantage of being explicit, and the disadvantage of
> requiring a bit more typing.
> (possibly passing in a "selftest *" param if we're doing the
> try-to-run-everything approach, so we can count failures etc without
> introducing globals)
>
> Was that what you had in mind, or something else?

It's one option, but it doesn't seem like the best one either. I was 
thinking of something not dissimilar to your approach, but with fewer 
bells and whistles. My class registrator would look something like this:

static list<void (*)()> test_callbacks;

class registrator
{
public:
   registrator (void (*)() cb)
   {
     test_callbacks.push_front (cb);
   }
}

(or use a vec if you can do that at global constructor time)

and then you just walk the list and run the callbacks when you want to 
run tests. The one you have implements both the registration and a 
special case linked list, which just doesn't look right to me, and I 
think I'd also have avoided the runner class.


Bernd

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 01/15] Selftest framework (unittests v4)
  2015-11-19 18:44                               ` Bernd Schmidt
@ 2015-11-19 20:04                                 ` Mikhail Maltsev
  2015-11-24 20:45                                 ` Jeff Law
  2015-11-25 22:53                                 ` David Malcolm
  2 siblings, 0 replies; 176+ messages in thread
From: Mikhail Maltsev @ 2015-11-19 20:04 UTC (permalink / raw)
  To: Bernd Schmidt, David Malcolm; +Cc: gcc-patches, Jeff Law

On 11/19/2015 09:44 PM, Bernd Schmidt wrote:
> It's one option, but it doesn't seem like the best one either. I was
> thinking of something not dissimilar to your approach, but with fewer
> bells and whistles. My class registrator would look something like this:
> 
> static list<void (*)()> test_callbacks;
> 
> class registrator
> {
> public:
>   registrator (void (*)() cb)
>   {
>     test_callbacks.push_front (cb);
>   }
> }
> 
> (or use a vec if you can do that at global constructor time)
> 
> and then you just walk the list and run the callbacks when you want to
> run tests. The one you have implements both the registration and a
> special case linked list, which just doesn't look right to me, and I
> think I'd also have avoided the runner class.

Google test allows to run tests which match a given regular expression.
This is very convenient when you debug a failing test: you just need to
run the testsuite under debugger and specify the relevant (failing) test
as a filter. I think this feature is worth implementing eventually
(maybe regex is an overkill, and matching against a substring will be
enough). So, if testcases are implemented as objects, it will easy to
add filtering. If testcases are just callbacks, names and possibly some
other metainformation need to be stored separately.

FWIW, I worked with other unit test frameworks, such as CppUnit (but
Google Test is superior, IMHO) and they use the same approach: testcases
are objects which store metainformation (such as name) and have methods
for running tests.

-- 
Regards,
    Mikhail Maltsev

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 02/15] Add selftests to bitmap.c
  2015-11-19 16:46                         ` [PATCH 02/15] Add selftests to bitmap.c David Malcolm
@ 2015-11-20 10:41                           ` Richard Biener
  2015-11-24 21:13                           ` Jeff Law
  1 sibling, 0 replies; 176+ messages in thread
From: Richard Biener @ 2015-11-20 10:41 UTC (permalink / raw)
  To: David Malcolm; +Cc: GCC Patches, Bernd Schmidt, Jeff Law

On Thu, Nov 19, 2015 at 6:04 PM, David Malcolm <dmalcolm@redhat.com> wrote:
> Jeff pre-approved the plugin version of this (as a new
> file unittests/test-bitmap.c):
>   https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03284.html
> with:
>> OK if/when prereqs are approved.  Minor twiddling if we end up moving it
>> elsewhere or standardizing/reducing header files is pre-approved.
>
> This version moves them to bitmap.c
>
> One issue: how to express:
>   TEST (bitmap_test, gc_alloc)
> in a ChangeLog entry.
>
> I've chosen to write it as (bitmap_test, gc_alloc) since that
> has the greatest chance of being found via grep.

I think overloading CHECKING_P for this is bogus.  Adding a new
UNIT_TEST_FILE (like GENERATOR_FILE) would be better.  Also
selftest.h should be only conditionally included (before the tests themselves?)

Richard.

> gcc/ChangeLog:
>         * bitmap.c: Include "selftest.h".
>         (bitmap_test, gc_alloc): New selftest.
>         (bitmap_test, set_range): New selftest.
>         (bitmap_test, clear_bit_in_middle): New selftest.
>         (bitmap_test, copying): New selftest.
>         (bitmap_test, bitmap_single_bit_set_p): New selftest.
> ---
>  gcc/bitmap.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 92 insertions(+)
>
> diff --git a/gcc/bitmap.c b/gcc/bitmap.c
> index f04b8f9..e6f772e 100644
> --- a/gcc/bitmap.c
> +++ b/gcc/bitmap.c
> @@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "system.h"
>  #include "coretypes.h"
>  #include "bitmap.h"
> +#include "selftest.h"
>
>  /* Memory allocation statistics purpose instance.  */
>  mem_alloc_description<bitmap_usage> bitmap_mem_desc;
> @@ -2094,5 +2095,96 @@ debug (const bitmap_head *ptr)
>      fprintf (stderr, "<nil>\n");
>  }
>
> +#if CHECKING_P
> +namespace {
> +
> +/* Freshly-created bitmaps ought to be empty.  */
> +
> +TEST (bitmap_test, gc_alloc)
> +{
> +  bitmap b = bitmap_gc_alloc ();
> +  EXPECT_TRUE (bitmap_empty_p (b));
> +}
> +
> +/* Verify bitmap_set_range.  */
> +
> +TEST (bitmap_test, set_range)
> +{
> +  bitmap b = bitmap_gc_alloc ();
> +  EXPECT_TRUE (bitmap_empty_p (b));
> +
> +  bitmap_set_range (b, 7, 5);
> +  EXPECT_FALSE (bitmap_empty_p (b));
> +  EXPECT_EQ (5, bitmap_count_bits (b));
> +
> +  /* Verify bitmap_bit_p at the boundaries.  */
> +  EXPECT_FALSE (bitmap_bit_p (b, 6));
> +  EXPECT_TRUE (bitmap_bit_p (b, 7));
> +  EXPECT_TRUE (bitmap_bit_p (b, 11));
> +  EXPECT_FALSE (bitmap_bit_p (b, 12));
> +}
> +
> +/* Verify splitting a range into two pieces using bitmap_clear_bit.  */
> +
> +TEST (bitmap_test, clear_bit_in_middle)
> +{
> +  bitmap b = bitmap_gc_alloc ();
> +
> +  /* Set b to [100..200].  */
> +  bitmap_set_range (b, 100, 100);
> +  EXPECT_EQ (100, bitmap_count_bits (b));
> +
> +  /* Clear a bit in the middle.  */
> +  bool changed = bitmap_clear_bit (b, 150);
> +  EXPECT_TRUE (changed);
> +  EXPECT_EQ (99, bitmap_count_bits (b));
> +  EXPECT_TRUE (bitmap_bit_p (b, 149));
> +  EXPECT_FALSE (bitmap_bit_p (b, 150));
> +  EXPECT_TRUE (bitmap_bit_p (b, 151));
> +}
> +
> +/* Verify bitmap_copy.  */
> +
> +TEST (bitmap_test, copying)
> +{
> +  bitmap src = bitmap_gc_alloc ();
> +  bitmap_set_range (src, 40, 10);
> +
> +  bitmap dst = bitmap_gc_alloc ();
> +  EXPECT_FALSE (bitmap_equal_p (src, dst));
> +  bitmap_copy (dst, src);
> +  EXPECT_TRUE (bitmap_equal_p (src, dst));
> +
> +  /* Verify that we can make them unequal again...  */
> +  bitmap_set_range (src, 70, 5);
> +  EXPECT_FALSE (bitmap_equal_p (src, dst));
> +
> +  /* ...and that changing src after the copy didn't affect
> +     the other: */
> +  EXPECT_FALSE (bitmap_bit_p (dst, 70));
> +}
> +
> +/* Verify bitmap_single_bit_set_p.  */
> +TEST (bitmap_test, bitmap_single_bit_set_p)
> +{
> +  bitmap b = bitmap_gc_alloc ();
> +
> +  EXPECT_FALSE (bitmap_single_bit_set_p (b));
> +
> +  bitmap_set_range (b, 42, 1);
> +  EXPECT_TRUE (bitmap_single_bit_set_p (b));
> +  EXPECT_EQ (42, bitmap_first_set_bit (b));
> +
> +  bitmap_set_range (b, 1066, 1);
> +  EXPECT_FALSE (bitmap_single_bit_set_p (b));
> +  EXPECT_EQ (42, bitmap_first_set_bit (b));
> +
> +  bitmap_clear_range (b, 0, 100);
> +  EXPECT_TRUE (bitmap_single_bit_set_p (b));
> +  EXPECT_EQ (1066, bitmap_first_set_bit (b));
> +}
> +
> +}  // anon namespace
> +#endif /* CHECKING_P */
>
>  #include "gt-bitmap.h"
> --
> 1.8.5.3
>

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 01/15] Selftest framework (unittests v4)
  2015-11-19 17:35                           ` Bernd Schmidt
  2015-11-19 18:08                             ` David Malcolm
@ 2015-11-24 20:29                             ` Jeff Law
  1 sibling, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-11-24 20:29 UTC (permalink / raw)
  To: Bernd Schmidt, David Malcolm, gcc-patches

On 11/19/2015 10:35 AM, Bernd Schmidt wrote:
> In general I'm much happier with this approach, and I think this series
> is close to ready, but I want to bring up some questions that could use
> wider discussion.
>
>> This patch adds a selftest.h/.c to gcc, with an API loosely
>> modelled on gtest (though without the use of CamelCase): it
>> supports enough of the gtest API to enable the tests that I
>> wrote to run with minimal changes.
And just to chime in a bit on this -- when David and I talked about 
gtest being used in this way, the problem we're going to run into is 
header file ordering, dependencies and the like.  It was a bit of a 
tangled mess.  It seemed easier to pull together a gtest-ish like 
framework that wasn't going to bump into those issues.


>
> Here there's a question of style. I don't want to approve or reject this
> just now, I'd like to hear what others think. To my eyes this still
> looks rather seriously overengineered. Plain gcc_assert and if (cond)
> abort (); would work just fine for the tests IMO, it's what we have for
> regular testcases where we don't distinguish between all sorts of
> microscopic subtests, and any gcc_assert failure is easy enough to
> debug, just load up cc1 into the debugger and run. I don't think we need
> output for tests that are really just expected to pass always, all we
> need is the build to stop if an internal error is detected.
But having a clearer pass/fail indication avoids the problem of "does no 
output mean everything passed or nothing ran"?  Though I guess we could 
fix this by having a clear pass/fail indicator that runs last and is 
controlled by the same mechanism as the testsuite as a whole.

I guess in the end, I don't have a clear preference.    Which probably 
argues that, for me, does this stuff make it easier or harder to write a 
test?


>
> If I'd written it I'd also have used a somewhat lower-tech approach for
> the registration and running of tests, but once again I'd like to hear
> from others.
I was a bit surprised by David's approach, but the more I think about 
it, auto-registration is actually a damn nice feature.

However, I do worry about state from one test leaking into a spoiling 
some later test.  I haven't looked closely to see if that's avoided, but 
it is definitely a worry.

>
> For things like
>
>> +#define RUN_ALL_TESTS() \
>> +  ::selftest::run_all_tests ()
>
> I don't see the point of the macro. Also, in [8/15]
>
>> +class gimple_test : public ::selftest::test
>> +{
>> + protected:
>> +  void
>> +  verify_gimple_pp (const char *expected, gimple *stmt)
>> +  {
>> +    pretty_printer pp;
>> +    pp_gimple_stmt_1 (&pp, stmt, 0 /* spc */, 0 /* flags */);
>> +    EXPECT_STREQ (expected, pp_formatted_text (&pp));
>> +  }
>> +};
>> +
>
> Why have the class rather than just a function? This sort of thing makes
> me go "overuse of C++".
Conceptually the ability to subclass is one of the key ways to introduce 
testing.   I'm not sure it's buying us much here (because we're not 
subclasing anything in GCC itself), but as an approach to getting 
subsystems under testing, subclassing is a vital capability.

jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 01/15] Selftest framework (unittests v4)
  2015-11-19 18:44                               ` Bernd Schmidt
  2015-11-19 20:04                                 ` Mikhail Maltsev
@ 2015-11-24 20:45                                 ` Jeff Law
  2015-11-25  2:43                                   ` David Malcolm
  2015-11-25  7:43                                   ` Trevor Saunders
  2015-11-25 22:53                                 ` David Malcolm
  2 siblings, 2 replies; 176+ messages in thread
From: Jeff Law @ 2015-11-24 20:45 UTC (permalink / raw)
  To: Bernd Schmidt, David Malcolm; +Cc: gcc-patches

On 11/19/2015 11:44 AM, Bernd Schmidt wrote:
> On 11/19/2015 07:08 PM, David Malcolm wrote:
>> gcc_assert terminates the process and no further testing is done,
>> whereas the approach the kit tries to run as much of the testsuite as
>> possible, and then fail if any errors occurred.
>
> Yeah, but let's say someone is working on bitmaps and one of the bitmap
> tests fail, it's somewhat unlikely that cfg will also fail (or if it
> does, it'll be a consequence of the earlier failure). You debug the
> issue, fix it, and run cc1 -fself-test again to see if that sorted it out.
>
> As I said, it's a matter of taste and style and I won't claim that my
> way is necessarily the right one, but I do want to see if others feel
> the same.
I was originally going to say that immediate abort would be the 
preferred method of operation, but as I thought more about it....

I think this really is a question of how the tests are likely used.  I 
kind of expect that most of the time they'll be used as part of an early 
sanity test.

So to continue with the bitmap botch causing a CFG failure, presumably 
the developer was mucking around in the bitmap code already and when 
they see the CFG test failure, they're going to suspect they've mucked 
up the bitmap code in some way.

The first question should then be did the bitmap tests pass or fail and 
if they passed, then those tests clearly need extending :-)

>
>> The patch kit does use a lot of "magic" via macros and C++.
>>
>> Taking registration/discovery/running in completely the other direction,
>> another approach could be a completely manual approach, with something
>> like this in toplev.c:
>>
>>    bitmap_selftest ();
>>    et_forest_selftest ();
>>    /* etc */
>>    vec_selftest ();
>>
>> This has the advantage of being explicit, and the disadvantage of
>> requiring a bit more typing.
The one advantage of explicit registration I see is the ability to order 
the tests so that the lowest level data structures are tested first, 
moving to increasingly more complex stuff.

But if we're in a mode of run everything, then ordering won't be that 
important.

In the end I think I lean towards run everything with automatic 
registration/discovery.  But I still have state worries.  Or to put it 
another way, given a test of tests, we should be able to run them in an 
arbitrary order with no changes in the expected output or pass/fail results.

jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 02/15] Add selftests to bitmap.c
  2015-11-19 16:46                         ` [PATCH 02/15] Add selftests to bitmap.c David Malcolm
  2015-11-20 10:41                           ` Richard Biener
@ 2015-11-24 21:13                           ` Jeff Law
  1 sibling, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-11-24 21:13 UTC (permalink / raw)
  To: David Malcolm, gcc-patches; +Cc: Bernd Schmidt

On 11/19/2015 10:04 AM, David Malcolm wrote:
> Jeff pre-approved the plugin version of this (as a new
> file unittests/test-bitmap.c):
>    https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03284.html
> with:
>> OK if/when prereqs are approved.  Minor twiddling if we end up moving it
>> elsewhere or standardizing/reducing header files is pre-approved.
>
> This version moves them to bitmap.c
>
> One issue: how to express:
>    TEST (bitmap_test, gc_alloc)
> in a ChangeLog entry.
>
> I've chosen to write it as (bitmap_test, gc_alloc) since that
> has the greatest chance of being found via grep.
Seems reasonable.  I'm not going to go through the individual tests 
closely this round.  I think the big question is whether or not we're 
getting close to an agreement on things like all tests vs stop at first 
failure, registration and pollution of state from one test to the next.

So what I like here is we've got a single #include, which probably 
should, by convention, be last in the set of headers.  Then at the end 
of the file we have the tests, guarded by a single #if CHECKING_P.

Each test uses the TEST macro, which is probably fine since it gives a 
way to hook up registration and the like.

EXPECT_XXX usage (or non-usage) will follow from the test everything vs 
stop at first failure decision.  If we adopt test everything, then 
indirection of some sort is useful here too as we can log results.

I'm curious what the namespace is for.  It's probably fine, just curious 
more than anything.

Jeff


^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 01/15] Selftest framework (unittests v4)
  2015-11-19 16:46                         ` [PATCH 01/15] Selftest framework (unittests v4) David Malcolm
  2015-11-19 17:35                           ` Bernd Schmidt
@ 2015-11-24 22:43                           ` Jeff Law
  1 sibling, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-11-24 22:43 UTC (permalink / raw)
  To: David Malcolm, gcc-patches; +Cc: Bernd Schmidt

On 11/19/2015 10:04 AM, David Malcolm wrote:
> This patch adds a selftest.h/.c to gcc, with an API loosely
> modelled on gtest (though without the use of CamelCase): it
> supports enough of the gtest API to enable the tests that I
> wrote to run with minimal changes.
I know it's small, but avoiding CamelCase is a plus in my book :-)

> Like gtest, tests are automatically discovered, using
> some global object ctor magic.  Sadly this doesn't work
> for some reason for source files which are purely tests, so
> as a nasty workaround I #include those files from toplev.c
That needs to be tracked down.


>
> I didn't document -fself-test; should I?  (maybe just in the
> internal docs?)
I'd document in the internals.

>
> This iteration of the patchkit doesn't yet do anything to
> automatically invoke -fself-test; I've been running it by hand
> when compiling an empty .c file, so it's been running inside cc1.
> How should this be hooked up?
It has to be hooked up within the gcc directory.    Presumably it's just 
a new Makefile target that "all" depends upon.    If the self-test 
fails, I think we should stop the build.  And when host != build I don't 
think we can run the self-tests.

The other option, and I'm hesitant to suggest it would be to run the 
selftest within the stanza that builds cc1.  I don't think this is a 
good idea.

>
> Currently -fself-test requires an input file; should it?  (But if not,
> what should the driver run?  All of them?).  Requiring an input file,
> and providing an empty one may be simplest.
I would think that -fself-test is a driver option.  Presumably this is 
going to be fast enough that the Makefile target just runs all of them.

>
> I anticipate a discussion about output formats; the current output
> format is deliberately very verbose, to ensure that we're capturing
> everything of interest.  It contains file/line info of each
> EXPECT/ASSERT so that it's easy in Emacs to click in the compilation
> buffer to go to specific assertions.
I guess I'll look at the line number as a feature rather than an 
annoyance for diffing.

> Potentially we could have some kind of verbosity flag for the
> selftests, I guess.
My inclination would be to keep the verbosity as long as its logging to 
a file by default.

>
> I did attempt to use "inform" to report results, but I don't think
> this is appropriate for the most verbose form of output:
> (A) some tests manipulate cfun and hence lead to strange
> "In function ..." messages as they run based on the changes to cfun
> (B) I want to write selftests for the diagnostics subsystem itself
Right.  I think we largely want to avoid using GCC's internals for test 
reporting.  So this seems right to me.

>>
> Notes on porting tests from gtest:
> * Fixtures inherit from ::selftest::test, rather than
>    from gtest's ::testing::Test
> * There's no support yet for Setup and Teardown vfuncs (which
>    presumably would be "setup" and "teardown")
> * I only implemented what I needed
> * I didn't implement type-parametrized testing, so for now
>    I've dropped test-wide-int.c (which is the only test I had
>    that was parametrized over multiple types).
>
> gcc/ChangeLog:
> 	* Makefile.in (OBJS-libcommon): Add selftest.o.
> 	(OBJS-libcommon-target): Add selftest.o.
> 	(COLLECT2_OBJS): Add selftest.o.
> 	* common.opt (fself-test): New.
> 	* selftest.c: New file.
> 	* selftest.h: New file.
> 	* toplev.c: Include selftest.h.  Add includes of function-tests.c,
> 	hash-map-tests.c, hash-set-tests.c, rtl-tests.c as a workaround
> 	for a linker issue.
> 	(toplev::run_self_tests): New.
> 	(toplev::main): Handle -fself-test.
> 	* toplev.h (toplev::run_self_tests): New.

  +#if CHECKING_P
> +
> +namespace selftest {
> +
> +class test;
> +class runner;
> +class registrator;
> +
> +/* The entrypoint for running all tests.  */
> +
> +extern int run_all_tests ();
> +
> +/* The class ::selftest::runner is responsible for gathering results,
> +   and for output.  */
> +
> +class runner
> +{
> +public:
> +  runner ();
> +  ~runner ();
> +
> +  void begin_test (test *t);
> +  void pass (const char *file, int line, test *t, const char *msg);
> +  void fail (const char *file, int line, test *t, const char *msg);
> +  void end_test (test *t);
Presumably we can extend this with an xfail if the need arises.  I'm 
thinking of stuff like "you can't change the underlying state of a 
bitmap while you're iterating on it".   I'm pretty sure I could write a 
test for this if I dug into my archives.  I've always considered it a 
bug in our implementation.

> +
> +/* Evaluate EXPECTED and ACTUAL and compare them with strcmp, issuing
> +   PASS if they are equal, FAIL if they are non-equal.  */
> +
> +#define EXPECT_STREQ(EXPECTED, ACTUAL)			       \
> +  SELFTEST_BEGIN_STMT					       \
> +  const char *desc = "EXPECT_STREQ (" #EXPECTED ", " #ACTUAL ")"; \
> +  const char *expected_ = (EXPECTED);				  \
> +  const char *actual_ = (ACTUAL);				  \
> +  if (0 == strcmp (expected_, actual_))				  \
> +    pass (__FILE__, __LINE__, desc);			       \
> +  else							       \
> +    fail (__FILE__, __LINE__, desc);			       \
> +  SELFTEST_END_STMT
nit, don't we typically write strcmp () == 0?

> @@ -1995,6 +1997,52 @@ toplev::start_timevars ()
>     timevar_start (TV_TOTAL);
>   }
>
> +/* For some tests, there's a natural source file to place them in.
> +   For others, they can live in their own "foo-tests.c" file.
> +   Ideally, these "foo-tests.c" files would be added to OBJS in
> +   Makefile.in.  However, for some reason that approach doesn't
> +   work: the tests don't get run..  The linker appears to be discarding
> +   the global "registrator" instances in files which are purely
> +   test cases (apart from ggc-tests.c, which works for some
> +   reason; perhaps the GC roots is poking the linker in such a way
> +   as to prevent the issue).
> +
> +   Hence as a workaround, we instead directly include the files here.  */
I'd really like to know the whys here before agreeing to the workaround.

Bernd has some stylistic comments as well.  I won't repeat them.

Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 01/15] Selftest framework (unittests v4)
  2015-11-24 20:45                                 ` Jeff Law
@ 2015-11-25  2:43                                   ` David Malcolm
  2015-11-25 10:56                                     ` Bernd Schmidt
  2015-11-25  7:43                                   ` Trevor Saunders
  1 sibling, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-11-25  2:43 UTC (permalink / raw)
  To: Jeff Law; +Cc: Bernd Schmidt, gcc-patches

On Tue, 2015-11-24 at 13:44 -0700, Jeff Law wrote:
> On 11/19/2015 11:44 AM, Bernd Schmidt wrote:
> > On 11/19/2015 07:08 PM, David Malcolm wrote:
> >> gcc_assert terminates the process and no further testing is done,
> >> whereas the approach the kit tries to run as much of the testsuite as
> >> possible, and then fail if any errors occurred.
> >
> > Yeah, but let's say someone is working on bitmaps and one of the bitmap
> > tests fail, it's somewhat unlikely that cfg will also fail (or if it
> > does, it'll be a consequence of the earlier failure). You debug the
> > issue, fix it, and run cc1 -fself-test again to see if that sorted it out.
> >
> > As I said, it's a matter of taste and style and I won't claim that my
> > way is necessarily the right one, but I do want to see if others feel
> > the same.
> I was originally going to say that immediate abort would be the 
> preferred method of operation, but as I thought more about it....
> 
> I think this really is a question of how the tests are likely used.  I 
> kind of expect that most of the time they'll be used as part of an early 
> sanity test.
> 
> So to continue with the bitmap botch causing a CFG failure, presumably 
> the developer was mucking around in the bitmap code already and when 
> they see the CFG test failure, they're going to suspect they've mucked 
> up the bitmap code in some way.

Consider the case where an assumption that the host is little-endian
assumption creeps into one of the bitmap functions.  Some time later,
another developer updates their working copy from svn on a big-endian
host and finds that lots of things are broken.  What's the ideal
behavior?


> The first question should then be did the bitmap tests pass or fail and 
> if they passed, then those tests clearly need extending :-)

Indeed, for the case above also.

> >
> >> The patch kit does use a lot of "magic" via macros and C++.
> >>
> >> Taking registration/discovery/running in completely the other direction,
> >> another approach could be a completely manual approach, with something
> >> like this in toplev.c:
> >>
> >>    bitmap_selftest ();
> >>    et_forest_selftest ();
> >>    /* etc */
> >>    vec_selftest ();
> >>
> >> This has the advantage of being explicit, and the disadvantage of
> >> requiring a bit more typing.
> The one advantage of explicit registration I see is the ability to order 
> the tests so that the lowest level data structures are tested first, 
> moving to increasingly more complex stuff.
> 
> But if we're in a mode of run everything, then ordering won't be that 
> important.
> 
> In the end I think I lean towards run everything with automatic 
> registration/discovery.  But I still have state worries.  Or to put it 
> another way, given a test of tests, we should be able to run them in an 
> arbitrary order with no changes in the expected output or pass/fail results.

That would be the ideal - though do we require randomization, or merely
hold it up as an ideal?  As it happens, I believe function-tests.c has
an ordering dependency (an rtl initialization assert, iirc), which
sorting them papered over.

Dave

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 01/15] Selftest framework (unittests v4)
  2015-11-24 20:45                                 ` Jeff Law
  2015-11-25  2:43                                   ` David Malcolm
@ 2015-11-25  7:43                                   ` Trevor Saunders
  1 sibling, 0 replies; 176+ messages in thread
From: Trevor Saunders @ 2015-11-25  7:43 UTC (permalink / raw)
  To: Jeff Law; +Cc: Bernd Schmidt, David Malcolm, gcc-patches

On Tue, Nov 24, 2015 at 01:44:34PM -0700, Jeff Law wrote:
> On 11/19/2015 11:44 AM, Bernd Schmidt wrote:
> >On 11/19/2015 07:08 PM, David Malcolm wrote:
> >>gcc_assert terminates the process and no further testing is done,
> >>whereas the approach the kit tries to run as much of the testsuite as
> >>possible, and then fail if any errors occurred.
> >
> >Yeah, but let's say someone is working on bitmaps and one of the bitmap
> >tests fail, it's somewhat unlikely that cfg will also fail (or if it
> >does, it'll be a consequence of the earlier failure). You debug the
> >issue, fix it, and run cc1 -fself-test again to see if that sorted it out.
> >
> >As I said, it's a matter of taste and style and I won't claim that my
> >way is necessarily the right one, but I do want to see if others feel
> >the same.
> I was originally going to say that immediate abort would be the preferred
> method of operation, but as I thought more about it....
In general I really dislike over engineering, andI kind of agree running
all the tests is that.  however looking at all the half way decent test
systems I'vedelt with I think they all supported it, so my guess is its
likely we'd end up adding this some day  Combining that with it not
beingtoo terrible to support it seems kind of harmless to build it in.

> I think this really is a question of how the tests are likely used.  I kind
> of expect that most of the time they'll be used as part of an early sanity
> test.
> 
> So to continue with the bitmap botch causing a CFG failure, presumably the
> developer was mucking around in the bitmap code already and when they see
> the CFG test failure, they're going to suspect they've mucked up the bitmap
> code in some way.
> 
> The first question should then be did the bitmap tests pass or fail and if
> they passed, then those tests clearly need extending :-)
> 
> >
> >>The patch kit does use a lot of "magic" via macros and C++.
> >>
> >>Taking registration/discovery/running in completely the other direction,
> >>another approach could be a completely manual approach, with something
> >>like this in toplev.c:
> >>
> >>   bitmap_selftest ();
> >>   et_forest_selftest ();
> >>   /* etc */
> >>   vec_selftest ();
> >>
> >>This has the advantage of being explicit, and the disadvantage of
> >>requiring a bit more typing.
> The one advantage of explicit registration I see is the ability to order the
> tests so that the lowest level data structures are tested first, moving to
> increasingly more complex stuff.
> 
> But if we're in a mode of run everything, then ordering won't be that
> important.
> 
> In the end I think I lean towards run everything with automatic
> registration/discovery.  But I still have state worries.  Or to put it
> another way, given a test of tests, we should be able to run them in an
> arbitrary order with no changes in the expected output or pass/fail results.

I haven't looked at the details of the auto registration, but assuming
its more or less the standard type thing I'd think we should be able to
support randomizing the test order pretty easily.  If we can easily run
the tests in a couple hundred random orders every month I'd think the
odds of inter test dependancies are fairly low.

Trev

> 
> jeff
> 

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 01/15] Selftest framework (unittests v4)
  2015-11-25  2:43                                   ` David Malcolm
@ 2015-11-25 10:56                                     ` Bernd Schmidt
  2015-11-25 16:57                                       ` Mike Stump
  2015-11-25 22:58                                       ` David Malcolm
  0 siblings, 2 replies; 176+ messages in thread
From: Bernd Schmidt @ 2015-11-25 10:56 UTC (permalink / raw)
  To: David Malcolm, Jeff Law; +Cc: gcc-patches

On 11/25/2015 03:26 AM, David Malcolm wrote:
> Consider the case where an assumption that the host is little-endian
> assumption creeps into one of the bitmap functions.  Some time later,
> another developer updates their working copy from svn on a big-endian
> host and finds that lots of things are broken.  What's the ideal
> behavior?

Internal compiler error in test_bitmaps, IMO. That's the quickest way to 
get to the right place in the debugger.

>> In the end I think I lean towards run everything with automatic
>> registration/discovery.  But I still have state worries.  Or to put it
>> another way, given a test of tests, we should be able to run them in an
>> arbitrary order with no changes in the expected output or pass/fail results.
>
> That would be the ideal - though do we require randomization, or merely
> hold it up as an ideal?  As it happens, I believe function-tests.c has
> an ordering dependency (an rtl initialization assert, iirc), which
> sorting them papered over.

What do you hope to gain with randomization? IMO if there are 
dependencies, we should be able to specify priority levels, which could 
also help running lower-level tests first.


Bernd

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 01/15] Selftest framework (unittests v4)
  2015-11-25 10:56                                     ` Bernd Schmidt
@ 2015-11-25 16:57                                       ` Mike Stump
  2015-11-29 18:10                                         ` Jeff Law
  2015-11-25 22:58                                       ` David Malcolm
  1 sibling, 1 reply; 176+ messages in thread
From: Mike Stump @ 2015-11-25 16:57 UTC (permalink / raw)
  To: Bernd Schmidt; +Cc: David Malcolm, Jeff Law, gcc-patches

On Nov 25, 2015, at 2:55 AM, Bernd Schmidt <bschmidt@redhat.com> wrote:
>> That would be the ideal - though do we require randomization

> What do you hope to gain with randomization?

Please, no randomization.

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 01/15] Selftest framework (unittests v4)
  2015-11-19 18:44                               ` Bernd Schmidt
  2015-11-19 20:04                                 ` Mikhail Maltsev
  2015-11-24 20:45                                 ` Jeff Law
@ 2015-11-25 22:53                                 ` David Malcolm
  2015-11-26 13:00                                   ` Bernd Schmidt
  2 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2015-11-25 22:53 UTC (permalink / raw)
  To: Bernd Schmidt; +Cc: gcc-patches, Jeff Law

On Thu, 2015-11-19 at 19:44 +0100, Bernd Schmidt wrote:
> On 11/19/2015 07:08 PM, David Malcolm wrote:
> > gcc_assert terminates the process and no further testing is done,
> > whereas the approach the kit tries to run as much of the testsuite as
> > possible, and then fail if any errors occurred.
> 
> Yeah, but let's say someone is working on bitmaps and one of the bitmap 
> tests fail, it's somewhat unlikely that cfg will also fail (or if it 
> does, it'll be a consequence of the earlier failure). You debug the 
> issue, fix it, and run cc1 -fself-test again to see if that sorted it out.
> 
> As I said, it's a matter of taste and style and I won't claim that my 
> way is necessarily the right one, but I do want to see if others feel 
> the same.
> 
> > The patch kit does use a lot of "magic" via macros and C++.
> >
> > Taking registration/discovery/running in completely the other direction,
> > another approach could be a completely manual approach, with something
> > like this in toplev.c:
> >
> >    bitmap_selftest ();
> >    et_forest_selftest ();
> >    /* etc */
> >    vec_selftest ();
> >
> > This has the advantage of being explicit, and the disadvantage of
> > requiring a bit more typing.
> > (possibly passing in a "selftest *" param if we're doing the
> > try-to-run-everything approach, so we can count failures etc without
> > introducing globals)
> >
> > Was that what you had in mind, or something else?
> 
> It's one option, but it doesn't seem like the best one either. I was 
> thinking of something not dissimilar to your approach, but with fewer 
> bells and whistles. My class registrator would look something like this:
> 
> static list<void (*)()> test_callbacks;
> 
> class registrator
> {
> public:
>    registrator (void (*)() cb)
>    {
>      test_callbacks.push_front (cb);
>    }
> }
> 
> (or use a vec if you can do that at global constructor time)
> 
> and then you just walk the list and run the callbacks when you want to 
> run tests. The one you have implements both the registration and a 
> special case linked list, which just doesn't look right to me, 

FWIW, the reason I special-cased the linked list was to avoid any
dynamic memory allocation: the ctors run before main, so I wanted to
keep them as simple as possible.  Putting the linked list directly into
those objects means that running the ctors is a simple case of wiring up
some pointers: the memory is already statically allocated.  (also, one
thing I want to test is vec<> itself [1]).

Anything more complicated feels to me like asking for trouble - and as
noted, I already have some bugs to track down with the linker apparently
optimizing away some tests.  (Maybe auto-registration is more trouble
than it's worth?)

> and I think I'd also have avoided the runner class.

The runner class was mostly about accumulating pass/fail information,
which goes back to the abort-on-first-failure vs try-to-run-everything
question.  If we do want the latter, it could be global state if that
would be simpler (though I prefer to avoid global state).

Dave

[1] although to be fair, I used vec<> in one place within the patch,
when sorting the tests.

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 01/15] Selftest framework (unittests v4)
  2015-11-25 10:56                                     ` Bernd Schmidt
  2015-11-25 16:57                                       ` Mike Stump
@ 2015-11-25 22:58                                       ` David Malcolm
  1 sibling, 0 replies; 176+ messages in thread
From: David Malcolm @ 2015-11-25 22:58 UTC (permalink / raw)
  To: Bernd Schmidt; +Cc: Jeff Law, gcc-patches

On Wed, 2015-11-25 at 11:55 +0100, Bernd Schmidt wrote:
> On 11/25/2015 03:26 AM, David Malcolm wrote:
> > Consider the case where an assumption that the host is little-endian
> > assumption creeps into one of the bitmap functions.  Some time later,
> > another developer updates their working copy from svn on a big-endian
> > host and finds that lots of things are broken.  What's the ideal
> > behavior?
> 
> Internal compiler error in test_bitmaps, IMO. That's the quickest way to 
> get to the right place in the debugger.
> 
> >> In the end I think I lean towards run everything with automatic
> >> registration/discovery.  But I still have state worries.  Or to put it
> >> another way, given a test of tests, we should be able to run them in an
> >> arbitrary order with no changes in the expected output or pass/fail results.
> >
> > That would be the ideal - though do we require randomization, or merely
> > hold it up as an ideal?  As it happens, I believe function-tests.c has
> > an ordering dependency (an rtl initialization assert, iirc), which
> > sorting them papered over.
> 
> What do you hope to gain with randomization? IMO if there are 
> dependencies, we should be able to specify priority levels, which could 
> also help running lower-level tests first.

I don't particularly want randomization, I was just wondering if others
wanted them, given that it's one of the features that test frameworks
tend to provide.

I do want some level of determinism over test ordering, for the sake of
everyone's sanity.  It's probably simplest to either hardcode the order,
or have priority levels.  I favor the former (and right now am leaning
towards a very explicit no-magic approach with no auto-registration,
given the linker issues I've been seeing with auto-registration).

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 01/15] Selftest framework (unittests v4)
  2015-11-25 22:53                                 ` David Malcolm
@ 2015-11-26 13:00                                   ` Bernd Schmidt
  2015-11-30 23:05                                     ` Jeff Law
  0 siblings, 1 reply; 176+ messages in thread
From: Bernd Schmidt @ 2015-11-26 13:00 UTC (permalink / raw)
  To: David Malcolm; +Cc: gcc-patches, Jeff Law

On 11/25/2015 11:47 PM, David Malcolm wrote:
> FWIW, the reason I special-cased the linked list was to avoid any
> dynamic memory allocation: the ctors run before main, so I wanted to
> keep them as simple as possible.

Is there any particular reason for this? C++ doesn't disallow memory 
allocation in global constructors, does it?

> Putting the linked list directly into
> those objects means that running the ctors is a simple case of wiring up
> some pointers: the memory is already statically allocated.  (also, one
> thing I want to test is vec<> itself [1]).

Ok so use a C++ list instead of a vec. My days of using C++ for personal 
projects are 15 years in the past so maybe I'm not an authority, but 
that's how I feel the language is supposed to be used - use provided 
data structures rather than coding them up over and over.

> I do want some level of determinism over test ordering, for the sake of
> everyone's sanity.  It's probably simplest to either hardcode the order,
> or have priority levels.  I favor the former (and right now am leaning
> towards a very explicit no-magic approach with no auto-registration,
> given the linker issues I've been seeing with auto-registration).

I guess that works too. Certainly explicit function calls are 
preferrable over #including other C files as a workaround for such a 
problem.

I still wish others would chime in on the rest of the issues we've 
discussed (run to first failure vs. providing elaborate test summaries), 
I want to make my preference clear but I don't want to dictate it.


Bernd

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 01/15] Selftest framework (unittests v4)
  2015-11-25 16:57                                       ` Mike Stump
@ 2015-11-29 18:10                                         ` Jeff Law
  0 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-11-29 18:10 UTC (permalink / raw)
  To: Mike Stump, Bernd Schmidt; +Cc: David Malcolm, gcc-patches

On 11/25/2015 09:50 AM, Mike Stump wrote:
> On Nov 25, 2015, at 2:55 AM, Bernd Schmidt <bschmidt@redhat.com> wrote:
>>> That would be the ideal - though do we require randomization
>
>> What do you hope to gain with randomization?
>
> Please, no randomization.
Agreed.

However, from a design standpoint, the tests must not depend on state 
from prior tests.   Thus, if someone were to report different unit 
testing results after randomizing the tests, then that's a bug (most 
likely in a test) that would need to be fixed.

jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 01/15] Selftest framework (unittests v4)
  2015-11-26 13:00                                   ` Bernd Schmidt
@ 2015-11-30 23:05                                     ` Jeff Law
  0 siblings, 0 replies; 176+ messages in thread
From: Jeff Law @ 2015-11-30 23:05 UTC (permalink / raw)
  To: Bernd Schmidt, David Malcolm; +Cc: gcc-patches

On 11/26/2015 05:37 AM, Bernd Schmidt wrote:
> On 11/25/2015 11:47 PM, David Malcolm wrote:
>> FWIW, the reason I special-cased the linked list was to avoid any
>> dynamic memory allocation: the ctors run before main, so I wanted to
>> keep them as simple as possible.
>
> Is there any particular reason for this? C++ doesn't disallow memory
> allocation in global constructors, does it?
I'm not aware of any such restriction, but I'm not a C++ guru.

David, what's the reason for avoiding dynamic memory allocation here?


>
>> I do want some level of determinism over test ordering, for the sake of
>> everyone's sanity.  It's probably simplest to either hardcode the order,
>> or have priority levels.  I favor the former (and right now am leaning
>> towards a very explicit no-magic approach with no auto-registration,
>> given the linker issues I've been seeing with auto-registration).
>
> I guess that works too. Certainly explicit function calls are
> preferrable over #including other C files as a workaround for such a
> problem.
My problem with priorities is that it's really just a poor man's 
substitution for dependency analysis. And in my experience, it usually 
fails.


> I still wish others would chime in on the rest of the issues we've
> discussed (run to first failure vs. providing elaborate test summaries),
> I want to make my preference clear but I don't want to dictate it.
I favor run-all over run-to-first-failure as long as we don't have good 
dependency analysis to order the tests.   That in turn tends to imply 
that each test ought to have a pass/fail indicator.

If we had good dependency analysis, then run-to-first-failure would be 
my preference.

Jeff

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 18/21] Add selftests to input.c
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
                                             ` (6 preceding siblings ...)
  2016-06-01 20:54                           ` [PATCH 20/21] Add selftests to tree.c David Malcolm
@ 2016-06-01 20:54                           ` David Malcolm
  2016-06-01 20:54                           ` [PATCH 01/21] Selftest framework (unittests v5) David Malcolm
                                             ` (14 subsequent siblings)
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 20:54 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff conditionally approved an earlier version of this (as
unittests/test-locations.c):
  https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03307.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files is
> pre-approved.
>
> Consider removing the stuff we aren't actually using. I think
> there was something simliar in another unittest file I looked at.

As before, this version moves the tests to the end of input.c, and
re-enables the __FILE__ access in location_test.

Doing so requires the selftest to be run from the build directory
so that e.g. cc1 can locate __FILE__.

New in this version is a fix for a bug in the reading_source_line test,
to avoid incorrectly assuming that source_line in 0-terminated.

gcc/ChangeLog:
	* input.c: Include "selftest.h".
	(class location_test): New test subclass.
	(location_test, accessing_ordinary_linemaps): New selftest.
	(location_test, unknown_location): New selftest.
	(location_test, builtins): New selftest.
	(location_test, reading_source_line): New selftest.
---
 gcc/input.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 110 insertions(+)

diff --git a/gcc/input.c b/gcc/input.c
index 61b1e44..b1d64a4 100644
--- a/gcc/input.c
+++ b/gcc/input.c
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "intl.h"
 #include "diagnostic-core.h"
+#include "selftest.h"
 
 /* This is a cache used by get_next_line to store the content of a
    file to be searched for file lines.  */
@@ -1136,3 +1137,112 @@ dump_location_info (FILE *stream)
   dump_labelled_location_range (stream, "AD-HOC LOCATIONS",
 				MAX_SOURCE_LOCATION + 1, UINT_MAX);
 }
+
+#if CHECKING_P
+
+namespace {
+
+/* Fixture for testing location-handling.
+   Creates some pre-canned location_t values.  */
+
+class location_test : public ::selftest::test
+{
+ protected:
+  location_test ()
+  {
+    /* Build a simple linemap describing some locations. */
+    linemap_add (line_table, LC_ENTER, false, "foo.c", 0);
+
+    linemap_line_start (line_table, 1, 100);
+    loc_a = linemap_position_for_column (line_table, 1);
+    loc_b = linemap_position_for_column (line_table, 23);
+
+    linemap_line_start (line_table, 2, 100);
+    loc_c = linemap_position_for_column (line_table, 1);
+    loc_d = linemap_position_for_column (line_table, 17);
+
+    /* Example of a very long line.  */
+    linemap_line_start (line_table, 3, 2000);
+    loc_e = linemap_position_for_column (line_table, 700);
+
+    linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+
+    /* Multiple files.  */
+    linemap_add (line_table, LC_ENTER, false, "bar.c", 0);
+    linemap_line_start (line_table, 1, 200);
+    loc_f = linemap_position_for_column (line_table, 150);
+    linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+  }
+
+  /* Verify the result of LOCATION_FILE/LOCATION_LINE/LOCATION_COLUMN
+     on LOC.  */
+  void
+  expect_loceq (const char *exp_filename,
+		int exp_linenum,
+		int exp_colnum,
+		location_t loc)
+  {
+    EXPECT_STREQ (exp_filename, LOCATION_FILE (loc));
+    EXPECT_EQ (exp_linenum, LOCATION_LINE (loc));
+    EXPECT_EQ (exp_colnum, LOCATION_COLUMN (loc));
+  }
+
+  location_t loc_a;
+  location_t loc_b;
+  location_t loc_c;
+  location_t loc_d;
+  location_t loc_e;
+  location_t loc_f;
+};
+
+/* Verify basic operation of ordinary linemaps.  */
+
+TEST_F (location_test, accessing_ordinary_linemaps)
+{
+  /* Verify that we can recover the location info.  */
+  expect_loceq ("foo.c", 1, 1, loc_a);
+  expect_loceq ("foo.c", 1, 23, loc_b);
+  expect_loceq ("foo.c", 2, 1, loc_c);
+  expect_loceq ("foo.c", 2, 17, loc_d);
+  expect_loceq ("foo.c", 3, 700, loc_e);
+  expect_loceq ("bar.c", 1, 150, loc_f);
+}
+
+TEST_F (location_test, unknown_location)
+{
+  EXPECT_EQ (NULL, LOCATION_FILE (UNKNOWN_LOCATION));
+  EXPECT_EQ (0, LOCATION_LINE (UNKNOWN_LOCATION));
+  EXPECT_EQ (0, LOCATION_COLUMN (UNKNOWN_LOCATION));
+}
+
+TEST_F (location_test, builtins)
+{
+  expect_loceq ("<built-in>", 0, 0, BUILTINS_LOCATION);
+  EXPECT_PRED1 (is_location_from_builtin_token, BUILTINS_LOCATION);
+  EXPECT_FALSE (is_location_from_builtin_token (loc_a));
+}
+
+/* Verify reading of input files (e.g. for caret-based diagnostics.  */
+
+TEST_F (location_test, reading_source_line)
+{
+  /* We will read *this* source file, using __FILE__.
+     Here is some specific text to read and test for:
+     The quick brown fox jumps over the lazy dog.  */
+  const int linenum_after_test_message = __LINE__;
+  const int linenum = linenum_after_test_message - 1;
+
+  int line_size;
+  const char *source_line = location_get_source_line (__FILE__, linenum, &line_size);
+  EXPECT_TRUE (source_line != NULL);
+  EXPECT_EQ (53, line_size);
+  if (!strncmp ("     The quick brown fox jumps over the lazy dog.  */",
+	       source_line, line_size))
+    pass (__FILE__, __LINE__, "source_line matched expected value");
+  else
+    fail (__FILE__, __LINE__, "source_line did not match expected value");
+}
+
+} /* anon namespace. */
+
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 02/21] Makefile.in integration
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
                                             ` (3 preceding siblings ...)
  2016-06-01 20:54                           ` [PATCH 03/21] Various selftest::runner tweaks David Malcolm
@ 2016-06-01 20:54                           ` David Malcolm
  2016-06-01 20:54                           ` [PATCH 17/21] Add hash-set-tests.c David Malcolm
                                             ` (17 subsequent siblings)
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 20:54 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Bernd said (in https://gcc.gnu.org/ml/gcc-patches/2015-11/msg01981.html ):
> For some of the simpler infrastructure tests such as the ones in this
> patch kit (bitmap, vec or wide-int functionality testing and such),
> we had the idea of putting these into every ENABLE_CHECKING compiler,
> and run them after building stage1, controlled by a -fself-test flag.
> It's better to detect such basic failures early rather than complete
> a full bootstrap and test cycle. It also keeps the tests alongside the
> rest of the implementation, which I consider desirable for such
> relatively simple data structures."

This patch implements this idea by adding a "selftests" phony target to
gcc/Makefile.in ensuring that the selftests must be successfully run for
the build to complete.
The time taken to run the testsuite is also printed.
A "s-selftests" file is created, so that the selftests need only be run
once each time "cc1" is rebuilt in a working copy.

They are run at each stage in a bootstrap.  For example, looking at a
bootstrap log:

 $ grep "fself-test:" test/experiment/x86_64-pc-linux-gnu/build/make.log
 -fself-test: 576 pass(es); 0 failure(s) in 0.028000 seconds
 -fself-test: 576 pass(es); 0 failure(s) in 0.009000 seconds
 -fself-test: 576 pass(es); 0 failure(s) in 0.011000 seconds

shows that the selftests are indeed run at each stage of a bootstrap,
and that they're fast (well under a second).

There's also a debug target, so that we can type:

  make selftests-gdb

to run the selftests under gdb.

For a release build, the "sorry" in toplev.c leads to an error, and hence
an effective failure.  Changing it to an "inform" fixes this.

gcc/ChangeLog:
	* Makefile.in (all.internal): Add "selftests".
	(all.cross): Likewise.
	(selftests): New phony target.
	(s-selftests): New target.
	(selftests-gdb): New phony target.
	* selftest.c (selftest::runner::runner): Initialize m_start_time.
	(selftest::runner::~runner): Print the elapsed time.
	* selftest.h (class selftest::runner): Add field "m_start_time".
	* toplev.c (toplev::run_self_tests): Use "inform" rather than "sorry"
	in an unchecked build.
---
 gcc/Makefile.in | 19 +++++++++++++++++--
 gcc/selftest.c  | 10 +++++++---
 gcc/selftest.h  |  1 +
 gcc/toplev.c    |  2 +-
 4 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 33dd75b..f01e123 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1817,10 +1817,10 @@ config.status: $(srcdir)/configure $(srcdir)/config.gcc
 quickstrap: all
 	cd $(toplevel_builddir) && $(MAKE) all-target-libgcc
 
-all.internal: start.encap rest.encap doc
+all.internal: start.encap rest.encap doc selftests
 # This is what to compile if making a cross-compiler.
 all.cross: native gcc-cross$(exeext) cpp$(exeext) specs \
-	libgcc-support lang.all.cross doc @GENINSRC@ srcextra
+	libgcc-support lang.all.cross doc selftests @GENINSRC@ srcextra
 # This is what must be made before installing GCC and converting libraries.
 start.encap: native xgcc$(exeext) cpp$(exeext) specs \
 	libgcc-support lang.start.encap @GENINSRC@ srcextra
@@ -1840,6 +1840,21 @@ endif
 # This does the things that can't be done on the host machine.
 rest.cross: specs
 
+# Run the selftests during the build once we have a driver and a cc1,
+# so that self-test failures are caught as early as possible.
+# Use "s-selftests" to ensure that we only run the selftests if the
+# driver or cc1 change.
+.PHONY: selftests
+selftests: s-selftests
+s-selftests: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs
+	$(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test
+	$(STAMP) $@
+
+# Convenience method for running selftests under gdb:
+.PHONY: selftests-gdb
+selftests-gdb: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs
+	$(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test -wrapper gdb,--args
+
 # Recompile all the language-independent object files.
 # This is used only if the user explicitly asks for it.
 compilations: $(BACKEND)
diff --git a/gcc/selftest.c b/gcc/selftest.c
index abb6585..af95312 100644
--- a/gcc/selftest.c
+++ b/gcc/selftest.c
@@ -80,7 +80,8 @@ selftest::run_all_tests ()
 
 runner::runner ()
 : m_passes (0),
-  m_failures (0)
+  m_failures (0),
+  m_start_time (get_run_time ())
 {
 }
 
@@ -88,8 +89,11 @@ runner::runner ()
 
 runner::~runner ()
 {
-  fprintf (stderr, "NOTE: %i pass(es); %i failure(s)\n",
-	   m_passes, m_failures);
+  long finish_time = get_run_time ();
+  long elapsed_time = finish_time - m_start_time;
+  fprintf (stderr, "NOTE: %i pass(es); %i failure(s) in %ld.%06ld seconds\n",
+	   m_passes, m_failures,
+	   elapsed_time / 1000000, elapsed_time % 1000000);
 }
 
 /* Notify the user that a particular test is about to be run.  */
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 884bdbf..720e1d5 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -54,6 +54,7 @@ public:
 private:
   int m_passes;
   int m_failures;
+  long m_start_time;
 };
 
 /* The class ::selftest::test is a base class from which specific
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 74712e5..ccb9c79 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -2079,7 +2079,7 @@ toplev::run_self_tests ()
   /* Cleanup.  */
   bitmap_obstack_release (NULL);
 #else
-  sorry ("self-tests are not enabled in this build");
+  inform (UNKNOWN_LOCATION, "self-tests are not enabled in this build");
 #endif /* #if CHECKING_P */
 }
 
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 03/21] Various selftest::runner tweaks.
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
                                             ` (2 preceding siblings ...)
  2016-06-01 20:54                           ` [PATCH 09/21] Add selftests to et-forest.c David Malcolm
@ 2016-06-01 20:54                           ` David Malcolm
  2016-06-01 20:54                           ` [PATCH 02/21] Makefile.in integration David Malcolm
                                             ` (18 subsequent siblings)
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 20:54 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

* move almost everything to a logfile (albeit without a way of
  setting it up yet)
* tweaks to failure-handling
* abort on failure

The practical upshot is that the output is much less verbose:
* if everything succeeds, the only output is of the form:
   -fself-test: 576 pass(es); 0 failure(s) in 0.028000 seconds
* if something fails, the failing test is identified on stderr,
  and the process immediately aborts (the idea being to make
  it easy to locate within the debugger).

gcc/ChangeLog:
	* selftest.c (runner::runner): Initialize m_logfile.
	(runner::~runner): Use m_logfile, with an alternate
	print to stderr if m_logfile is NULL.
	(runner::begin_test): Log to m_logfile, and conditionalize
	it on m_logfile being non-NULL.
	(runner::pass): Likewise.
	(runner::end_test): Likewise.
	(runner::fail): Use m_logfile if non-NULL, stderr otherwise.
	Abort on failure.
	* selftest.h (selftest::runner): Add field m_logfile.
---
 gcc/selftest.c | 31 +++++++++++++++++++++++--------
 gcc/selftest.h |  1 +
 2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/gcc/selftest.c b/gcc/selftest.c
index af95312..42e07e3 100644
--- a/gcc/selftest.c
+++ b/gcc/selftest.c
@@ -81,7 +81,8 @@ selftest::run_all_tests ()
 runner::runner ()
 : m_passes (0),
   m_failures (0),
-  m_start_time (get_run_time ())
+  m_start_time (get_run_time ()),
+  m_logfile (NULL)
 {
 }
 
@@ -91,9 +92,16 @@ runner::~runner ()
 {
   long finish_time = get_run_time ();
   long elapsed_time = finish_time - m_start_time;
-  fprintf (stderr, "NOTE: %i pass(es); %i failure(s) in %ld.%06ld seconds\n",
-	   m_passes, m_failures,
-	   elapsed_time / 1000000, elapsed_time % 1000000);
+  if (m_logfile)
+    fprintf (m_logfile,
+	     "NOTE: %i pass(es); %i failure(s) in %ld.%06ld seconds\n",
+	     m_passes, m_failures,
+	     elapsed_time / 1000000, elapsed_time % 1000000);
+  else
+    fprintf (stderr,
+	     "-fself-test: %i pass(es); %i failure(s) in %ld.%06ld seconds\n",
+	     m_passes, m_failures,
+	     elapsed_time / 1000000, elapsed_time % 1000000);
 }
 
 /* Notify the user that a particular test is about to be run.  */
@@ -101,7 +109,8 @@ runner::~runner ()
 void
 runner::begin_test (test *t)
 {
-  fprintf (stderr, "NOTE: %s: test starting\n", t->get_name ());
+  if (m_logfile)
+    fprintf (m_logfile, "NOTE: %s: test starting\n", t->get_name ());
 }
 
 /* Record and report the successful outcome of some aspect of a test.  */
@@ -109,7 +118,9 @@ runner::begin_test (test *t)
 void
 runner::pass (const char *file, int line, test *t, const char *msg)
 {
-  fprintf (stderr, "%s:%i: PASS: %s: %s\n", file, line, t->get_name (), msg);
+  if (m_logfile)
+    fprintf (m_logfile, "%s:%i: PASS: %s: %s\n",
+	     file, line, t->get_name (), msg);
   m_passes++;
 }
 
@@ -118,8 +129,11 @@ runner::pass (const char *file, int line, test *t, const char *msg)
 void
 runner::fail (const char *file, int line, test *t, const char *msg)
 {
-  fprintf (stderr, "%s:%i: FAIL: %s: %s\n", file, line, t->get_name (), msg);
+  fprintf (m_logfile ? m_logfile : stderr,
+	   "%s:%i: FAIL: %s: %s\n",
+	   file, line, t->get_name (), msg);
   m_failures++;
+  abort ();
 }
 
 /* Notify the user that a particular test has finished running.  */
@@ -127,7 +141,8 @@ runner::fail (const char *file, int line, test *t, const char *msg)
 void
 runner::end_test (test *t)
 {
-  fprintf (stderr, "NOTE: %s: test ending\n", t->get_name ());
+  if (m_logfile)
+    fprintf (m_logfile, "NOTE: %s: test ending\n", t->get_name ());
 }
 
 /* Implementation of class ::selftest::registrator.  */
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 720e1d5..95262ce 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -55,6 +55,7 @@ private:
   int m_passes;
   int m_failures;
   long m_start_time;
+  FILE *m_logfile;
 };
 
 /* The class ::selftest::test is a base class from which specific
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 10/21] Add selftests to fold-const.c
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
                                             ` (8 preceding siblings ...)
  2016-06-01 20:54                           ` [PATCH 01/21] Selftest framework (unittests v5) David Malcolm
@ 2016-06-01 20:54                           ` David Malcolm
  2016-06-01 21:09                           ` [PATCH 12/21] Fix warning in function-tests.c David Malcolm
                                             ` (12 subsequent siblings)
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 20:54 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an older version of this (as a separate
unittests/test-folding.c):
 https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03305.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files
> is pre-approved.

gcc/ChangeLog:
	* fold-const.c: Include "selftest.h".
	(class tree_folding_test): New test subclass.
	(tree_folding_test, arithmetic_folding): New selftest.
---
 gcc/fold-const.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)

diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 8a7c93e..91ca5cb 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -76,6 +76,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "case-cfn-macros.h"
 #include "stringpool.h"
 #include "tree-ssanames.h"
+#include "selftest.h"
 
 #ifndef LOAD_EXTEND_OP
 #define LOAD_EXTEND_OP(M) UNKNOWN
@@ -14455,3 +14456,68 @@ c_getstr (tree src)
 
   return TREE_STRING_POINTER (src) + tree_to_uhwi (offset_node);
 }
+
+#if CHECKING_P
+
+namespace {
+
+/* A test fixture for writing tests of folding trees.  */
+class tree_folding_test : public ::selftest::test
+{
+ protected:
+  void
+  assert_binop_folds_to_const (tree lhs, enum tree_code code, tree rhs,
+			       tree constant)
+  {
+    EXPECT_EQ (constant, fold_build2 (code, TREE_TYPE (lhs), lhs, rhs));
+  }
+
+  void
+  assert_binop_folds_to_nonlvalue (tree lhs, enum tree_code code, tree rhs,
+				   tree wrapped_expr)
+  {
+    tree result = fold_build2 (code, TREE_TYPE (lhs), lhs, rhs);
+    EXPECT_NE (wrapped_expr, result);
+    EXPECT_EQ (NON_LVALUE_EXPR, TREE_CODE (result));
+    EXPECT_EQ (wrapped_expr, TREE_OPERAND (result, 0));
+  }
+};
+
+TEST_F (tree_folding_test, arithmetic_folding)
+{
+  tree type = integer_type_node;
+  tree x = create_tmp_var_raw (type, "x");
+  tree zero = build_zero_cst (type);
+  tree one = build_int_cst (type, 1);
+
+  /* Addition.  */
+  /* 1 <-- (0 + 1) */
+  assert_binop_folds_to_const (zero, PLUS_EXPR, one,
+			       one);
+  assert_binop_folds_to_const (one, PLUS_EXPR, zero,
+			       one);
+
+  /* (nonlvalue)x <-- (x + 0) */
+  assert_binop_folds_to_nonlvalue (x, PLUS_EXPR, zero,
+				   x);
+
+  /* Subtraction.  */
+  /* 0 <-- (x - x) */
+  assert_binop_folds_to_const (x, MINUS_EXPR, x,
+			       zero);
+  assert_binop_folds_to_nonlvalue (x, MINUS_EXPR, zero,
+				   x);
+
+  /* Multiplication.  */
+  /* 0 <-- (x * 0) */
+  assert_binop_folds_to_const (x, MULT_EXPR, zero,
+			       zero);
+
+  /* (nonlvalue)x <-- (x * 1) */
+  assert_binop_folds_to_nonlvalue (x, MULT_EXPR, one,
+				   x);
+}
+
+}  // anon namespace
+
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 07/21] Add selftests to bitmap.c
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
@ 2016-06-01 20:54                           ` David Malcolm
  2016-06-01 20:54                           ` [PATCH 04/21] Add -fself-test-regex= David Malcolm
                                             ` (21 subsequent siblings)
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 20:54 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff pre-approved the plugin version of this (as a new
file unittests/test-bitmap.c):
  https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03284.html
with:
> OK if/when prereqs are approved.  Minor twiddling if we end up moving it
> elsewhere or standardizing/reducing header files is pre-approved.

This version moves them to bitmap.c

One issue: how to express:
  TEST (bitmap_test, gc_alloc)
in a ChangeLog entry.

I've chosen to write it as (bitmap_test, gc_alloc) since that
has the greatest chance of being found via grep.

gcc/ChangeLog:
	* bitmap.c: Include "selftest.h".
	(bitmap_test, gc_alloc): New selftest.
	(bitmap_test, set_range): New selftest.
	(bitmap_test, clear_bit_in_middle): New selftest.
	(bitmap_test, copying): New selftest.
	(bitmap_test, bitmap_single_bit_set_p): New selftest.
---
 gcc/bitmap.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/gcc/bitmap.c b/gcc/bitmap.c
index 0c05512..7db7c68 100644
--- a/gcc/bitmap.c
+++ b/gcc/bitmap.c
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "bitmap.h"
+#include "selftest.h"
 
 /* Memory allocation statistics purpose instance.  */
 mem_alloc_description<bitmap_usage> bitmap_mem_desc;
@@ -2162,5 +2163,96 @@ debug (const bitmap_head *ptr)
     fprintf (stderr, "<nil>\n");
 }
 
+#if CHECKING_P
+namespace {
+
+/* Freshly-created bitmaps ought to be empty.  */
+
+TEST (bitmap_test, gc_alloc)
+{
+  bitmap b = bitmap_gc_alloc ();
+  EXPECT_TRUE (bitmap_empty_p (b));
+}
+
+/* Verify bitmap_set_range.  */
+
+TEST (bitmap_test, set_range)
+{
+  bitmap b = bitmap_gc_alloc ();
+  EXPECT_TRUE (bitmap_empty_p (b));
+
+  bitmap_set_range (b, 7, 5);
+  EXPECT_FALSE (bitmap_empty_p (b));
+  EXPECT_EQ (5, bitmap_count_bits (b));
+
+  /* Verify bitmap_bit_p at the boundaries.  */
+  EXPECT_FALSE (bitmap_bit_p (b, 6));
+  EXPECT_TRUE (bitmap_bit_p (b, 7));
+  EXPECT_TRUE (bitmap_bit_p (b, 11));
+  EXPECT_FALSE (bitmap_bit_p (b, 12));
+}
+
+/* Verify splitting a range into two pieces using bitmap_clear_bit.  */
+
+TEST (bitmap_test, clear_bit_in_middle)
+{
+  bitmap b = bitmap_gc_alloc ();
+
+  /* Set b to [100..200].  */
+  bitmap_set_range (b, 100, 100);
+  EXPECT_EQ (100, bitmap_count_bits (b));
+
+  /* Clear a bit in the middle.  */
+  bool changed = bitmap_clear_bit (b, 150);
+  EXPECT_TRUE (changed);
+  EXPECT_EQ (99, bitmap_count_bits (b));
+  EXPECT_TRUE (bitmap_bit_p (b, 149));
+  EXPECT_FALSE (bitmap_bit_p (b, 150));
+  EXPECT_TRUE (bitmap_bit_p (b, 151));
+}
+
+/* Verify bitmap_copy.  */
+
+TEST (bitmap_test, copying)
+{
+  bitmap src = bitmap_gc_alloc ();
+  bitmap_set_range (src, 40, 10);
+
+  bitmap dst = bitmap_gc_alloc ();
+  EXPECT_FALSE (bitmap_equal_p (src, dst));
+  bitmap_copy (dst, src);
+  EXPECT_TRUE (bitmap_equal_p (src, dst));
+
+  /* Verify that we can make them unequal again...  */
+  bitmap_set_range (src, 70, 5);
+  EXPECT_FALSE (bitmap_equal_p (src, dst));
+
+  /* ...and that changing src after the copy didn't affect
+     the other: */
+  EXPECT_FALSE (bitmap_bit_p (dst, 70));
+}
+
+/* Verify bitmap_single_bit_set_p.  */
+TEST (bitmap_test, bitmap_single_bit_set_p)
+{
+  bitmap b = bitmap_gc_alloc ();
+
+  EXPECT_FALSE (bitmap_single_bit_set_p (b));
+
+  bitmap_set_range (b, 42, 1);
+  EXPECT_TRUE (bitmap_single_bit_set_p (b));
+  EXPECT_EQ (42, bitmap_first_set_bit (b));
+
+  bitmap_set_range (b, 1066, 1);
+  EXPECT_FALSE (bitmap_single_bit_set_p (b));
+  EXPECT_EQ (42, bitmap_first_set_bit (b));
+
+  bitmap_clear_range (b, 0, 100);
+  EXPECT_TRUE (bitmap_single_bit_set_p (b));
+  EXPECT_EQ (1066, bitmap_first_set_bit (b));
+}
+
+}  // anon namespace
+#endif /* CHECKING_P */
 
 #include "gt-bitmap.h"
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 04/21] Add -fself-test-regex=
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
  2016-06-01 20:54                           ` [PATCH 07/21] Add selftests to bitmap.c David Malcolm
@ 2016-06-01 20:54                           ` David Malcolm
  2016-06-01 20:54                           ` [PATCH 09/21] Add selftests to et-forest.c David Malcolm
                                             ` (20 subsequent siblings)
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 20:54 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

This patch adds a way to only run a subset of the tests,
by matching a regex against test names.

This can also be used to run just one test.

gcc/ChangeLog:
	* common.opt (fself-test-regex=): New option.
	* selftest.c: Include diagnostic.h, xregex.h, options.h.
	(get_regerror): New function.
	(selftest::run_all_tests): Rename to...
	(selftest::run_tests): ...this, and add param REGEX_PATTERN,
	using it to filter the tests if non-NULL.
	* selftest.h (selftest::run_all_tests): Rename to...
	(selftest::run_tests): ...this, adding param REGEX_PATTERN.
	* toplev.c (toplev::run_self_tests): Update for above changes.
---
 gcc/common.opt |  4 ++++
 gcc/selftest.c | 45 ++++++++++++++++++++++++++++++++++++++++++---
 gcc/selftest.h |  7 ++++---
 gcc/toplev.c   |  2 +-
 4 files changed, 51 insertions(+), 7 deletions(-)

diff --git a/gcc/common.opt b/gcc/common.opt
index 95376bf..6aaf8e6 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2061,6 +2061,10 @@ fself-test
 Common Var(flag_self_test)
 Run self-tests.
 
+fself-test-regex=
+Common RejectNegative Joined Var(self_test_regex)
+Run self-tests matching the given regex.
+
 fsel-sched-pipelining
 Common Report Var(flag_sel_sched_pipelining) Init(0) Optimization
 Perform software pipelining of inner loops during selective scheduling.
diff --git a/gcc/selftest.c b/gcc/selftest.c
index 42e07e3..ada0b9b 100644
--- a/gcc/selftest.c
+++ b/gcc/selftest.c
@@ -21,12 +21,15 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "selftest.h"
+#include "diagnostic.h"
+#include "xregex.h"
+#include "options.h"
 
 #if CHECKING_P
 
 using namespace selftest;
 
-/* Helper function for ::selftest::run_all_tests.  */
+/* Helper function for ::selftest::run_tests.  */
 
 static int
 test_comparator (const void *p1, const void *p2)
@@ -36,11 +39,24 @@ test_comparator (const void *p1, const void *p2)
   return strcmp (t1->get_name (), t2->get_name ());
 }
 
-/* Locate and run all tests.
+/* Generate an error message describing a failed attempt to compile a
+   regex.  The return value should be freed.  */
+
+static char *
+get_regerror (int errcode, regex_t *compiled)
+{
+  size_t length = regerror (errcode, compiled, NULL, 0);
+  char *buffer = (char *)xmalloc (length);
+  (void) regerror (errcode, compiled, buffer, length);
+  return buffer;
+}
+
+/* Locate and run tests.  If REGEX_PATTERN is NULL, all tests are run.
+   Otherwise, only tests with names matching the regex are run.
    Return the number of failures that occurred.  */
 
 int
-selftest::run_all_tests ()
+selftest::run_tests (const char *regex_pattern)
 {
   /* Create all the tests, in an arbitrary order (based on
      the order of construction of the global "registrator" instances).  */
@@ -57,11 +73,31 @@ selftest::run_all_tests ()
   /* Sort the tests into a predictable order.  */
   tests.qsort (test_comparator);
 
+  regex_t regex;
+  if (regex_pattern)
+    {
+      int errcode = regcomp (&regex, regex_pattern, 0);
+      if (errcode)
+	{
+	  char *errmsg = get_regerror (errcode, &regex);
+	  error ("error compiling regex pattern %qs: %s", regex_pattern, errmsg);
+	  free (errmsg);
+	  return 1;
+	}
+    }
+
   /* Run all the tests, in order.  */
   unsigned i;
   test *t;
   FOR_EACH_VEC_ELT (tests, i, t)
     {
+      if (regex_pattern)
+	{
+	  int err = regexec (&regex, t->get_name (), 0, NULL, 0);
+	  if (err)
+	    /* Test did not match.  */
+	    continue;
+	}
       r.begin_test (t);
       t->run ();
       r.end_test (t);
@@ -71,6 +107,9 @@ selftest::run_all_tests ()
   FOR_EACH_VEC_ELT (tests, i, t)
     delete t;
 
+  if (regex_pattern)
+    regfree (&regex);
+
   return r.get_num_failures ();
 }
 
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 95262ce..aa0232a 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -31,9 +31,10 @@ class test;
 class runner;
 class registrator;
 
-/* The entrypoint for running all tests.  */
+/* The entrypoint for running all tests, or all tests matching
+   REGEX_PATTERN.  */
 
-extern int run_all_tests ();
+extern int run_tests (const char *regex_pattern);
 
 /* The class ::selftest::runner is responsible for gathering results,
    and for output.  */
@@ -93,7 +94,7 @@ class test
    Global instances are created via the REGISTER_TEST below.
    The constructor runs before main, wiring them up into a
    singly-linked list, which can be traversed by
-   ::selftest::run_all_tests.  */
+   ::selftest::run_tests.  */
 
 class registrator
 {
diff --git a/gcc/toplev.c b/gcc/toplev.c
index ccb9c79..e240b98 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -2069,7 +2069,7 @@ toplev::run_self_tests ()
   bitmap_obstack_initialize (NULL);
 
   /* Run the tests.  */
-  int result = ::selftest::run_all_tests ();
+  int result = ::selftest::run_tests (self_test_regex);
 
   /* Ensure that a test failure leads to the process exiting with
      a non-zero exit code.  */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 20/21] Add selftests to tree.c
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
                                             ` (5 preceding siblings ...)
  2016-06-01 20:54                           ` [PATCH 17/21] Add hash-set-tests.c David Malcolm
@ 2016-06-01 20:54                           ` David Malcolm
  2016-06-01 20:54                           ` [PATCH 18/21] Add selftests to input.c David Malcolm
                                             ` (15 subsequent siblings)
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 20:54 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-tree.c):
 https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03303.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files is
> pre-approved.

This version puts the tests at the end of tree.c.

gcc/ChangeLog:
	* tree.c: Include "selftest.h".
	(tree_test, integer_constants): New selftest.
	(tree_test, identifiers): New selftest.
	(tree_test, labels): New selftest.
---
 gcc/tree.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/gcc/tree.c b/gcc/tree.c
index 5a1d167..35e819c 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -61,6 +61,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "print-tree.h"
 #include "ipa-utils.h"
+#include "selftest.h"
 
 /* Tree code classes.  */
 
@@ -14179,4 +14180,50 @@ combined_fn_name (combined_fn fn)
     return internal_fn_name (as_internal_fn (fn));
 }
 
+#if CHECKING_P
+
+namespace {
+
+/* Verify that integer constants are sane.  */
+
+TEST (tree_test, integer_constants)
+{
+  ASSERT_TRUE (integer_type_node != NULL);
+  EXPECT_TRUE (build_int_cst (integer_type_node, 0) != NULL);
+
+  tree type = integer_type_node;
+
+  tree zero = build_zero_cst (type);
+  EXPECT_EQ (INTEGER_CST, TREE_CODE (zero));
+  EXPECT_EQ (type, TREE_TYPE (zero));
+
+  tree one = build_int_cst (type, 1);
+  EXPECT_EQ (INTEGER_CST, TREE_CODE (one));
+  EXPECT_EQ (type, TREE_TYPE (zero));
+}
+
+/* Verify identifiers.  */
+
+TEST (tree_test, identifiers)
+{
+  tree identifier = get_identifier ("foo");
+  EXPECT_EQ (3, IDENTIFIER_LENGTH (identifier));
+  EXPECT_STREQ ("foo", IDENTIFIER_POINTER (identifier));
+}
+
+/* Verify LABEL_DECL.  */
+
+TEST (tree_test, labels)
+{
+  tree identifier = get_identifier ("err");
+  tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
+				identifier, void_type_node);
+  EXPECT_EQ (-1, LABEL_DECL_UID (label_decl));
+  EXPECT_FALSE (FORCED_LABEL (label_decl));
+}
+
+}  // anon namespace
+
+#endif /* CHECKING_P */
+
 #include "gt-tree.h"
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5)
  2015-11-19 16:46                       ` [PATCH 00/15] Unittests framework v4: -fself-test David Malcolm
                                           ` (14 preceding siblings ...)
  2015-11-19 17:03                         ` [PATCH 11/15] Add selftests to input.c David Malcolm
@ 2016-06-01 20:54                         ` David Malcolm
  2016-06-01 20:54                           ` [PATCH 07/21] Add selftests to bitmap.c David Malcolm
                                             ` (22 more replies)
  15 siblings, 23 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 20:54 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

This is effectively v5 of the unittests proposal; for the earlier
versions see:
 * v1: https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00765.html
 * v2: https://gcc.gnu.org/ml/gcc-patches/2015-06/msg01224.html
 * v3: https://gcc.gnu.org/ml/gcc-patches/2015-10/msg02947.html
 * v4: https://gcc.gnu.org/ml/gcc-patches/2015-11/msg02379.html

Bernd said (in https://gcc.gnu.org/ml/gcc-patches/2015-11/msg01981.html ):
> For some of the simpler infrastructure tests such as the ones in this
> patch kit (bitmap, vec or wide-int functionality testing and such),
> we had the idea of putting these into every ENABLE_CHECKING compiler,
> and run them after building stage1, controlled by a -fself-test flag.
> It's better to detect such basic failures early rather than complete
> a full bootstrap and test cycle. It also keeps the tests alongside the
> rest of the implementation, which I consider desirable for such
> relatively simple data structures."

So the main difference is this version of the patch kit is that the tests
are run much earlier: rather than have a DejaGnu test below gcc.dg that
compiles a dummy file with -fself-test, in this iteration, gcc/Makefile.in
is updated so that the selftests are run during the build.

The patch kit adds a "selftests" phony target to gcc/Makefile.in
ensuring that the selftests must be successfully run for the build to complete.
The time taken to run the testsuite is also printed.
A "s-selftests" file is created, so that the selftests need only be run
once each time "cc1" is rebuilt in a working copy.

They are run at each stage in a bootstrap.  For example, looking at a
bootstrap log:

 $ grep "fself-test:" test/experiment/x86_64-pc-linux-gnu/build/make.log
 -fself-test: 522 pass(es); 0 failure(s) in 0.013000 seconds
 -fself-test: 522 pass(es); 0 failure(s) in 0.006000 seconds
 -fself-test: 522 pass(es); 0 failure(s) in 0.006000 seconds

shows that the selftests are indeed run at each stage of a bootstrap,
and that they're fast (well under a second).

There's also a debug target, so that we can type:

  make selftests-gdb

to run the selftests under gdb.

I also patched things so that it aborts on the first failure, making
failures easy to track down in the debugger, though requiring us to
make the selftests robust.

Assuming that other people like these changes, it has a few
implications:
* selftests ought to be fast.  We don't want to slow down the build.
* running -fself-test should be terse by default; we may want an option
  for it to be more verbose
* poorly written selftests could break the build for other people
  (e.g. accidentally making target-specific assumptions).

The patch kit adds some new tests:
* some self-tests for diagnostic-show-locus.c.  This shows how to unit-test
  an internal API.
* conversion of the Levenshtein selftest from a plugin to using
  -fself-test (we could move various other tests from plugins to run
  earlier).

There is a bug with GNU ld in which it doesn't run tests in source files
that purely contain tests (hence I was #include-ing these from toplev.c).
I tracked down the issue, which I've filed against GNU ld here:
   https://sourceware.org/bugzilla/show_bug.cgi?id=20152
and a minimal reproducer can be seen here:
   https://github.com/davidmalcolm/test-ctor
The issue is that these don't work with GNU ld if they're linked into
a .a file (libbackend.a in our case) and then linked from there into
cc1.  They work if they're linked directly into cc1 without going through
an archive.
We could link these files directly into cc1, or we could move to
manual test registration instead.
Or we could not have registration, and simply hardcode what tests run,
and what order they run in.

Testing:
  * successfully bootstrapped&regression tested on x86_64-pc-linux-gnu.
  * successfully built with 193 configurations using
    contrib/config-list.mk.  The remaining configurations fail for
    various reasons:
    * 9 vxworks configurations fail to run the selftests with:
        xgcc: fatal error: environment variable ‘WIND_BASE’ not defined
    * 4 configurations fail due to pre-existing warnings: fails on 3
      configurations (microblaze and rl78) due to warnings which I've
      posted fixes for), and on avr-rtemsOPT-enable-obsolete due to a
      different pair of warnings.
    * 2 failures: rs6000-ibm-aix4.3 and rs6000-ibm-aix5.1.0 due to a
      pre-existing bug on trunk (I've filed this as PR target/71375).
  * I haven't yet tested this with build != host.

Patch 1 is the main part of the implementation; it's similar to v4.
Patch 2 adds the new Makefile.in integration.
Patch 3 reduces the verbosity of the tests by moving almost all logging
to a new optional logfile (without providing a way to set it at this
stage).
Patch 4 shows a way of filtering the tests using a command-line regex.
Patch 5 adds a new example test, showing how to unit-test an
implementation detail of diagnostic-show-locus.c
Patch 6 shows an example of porting one of our existing plugin-based
tests to be within -fself-test instead.
Patches 7-21 are the previously posted tests, albeit with some bug
fixes.

My recollection is that the major unresolved discussion areas in v4
of the patch kit were:

(a) do we want to stop running at the first failure, or to run the
    testsuite to completion?

(b) should tests be automatically registered, or should this be manual?

(c) is this over-engineered; should we simply use gcc_assert etc?

For (a), this version of the patch kit switches to stopping at the
first failure.
For (b), this version of the patch kit stays with auto-registration.
For (c), this version stays with a "lite" version of GTest.

Thoughts?   Does the "running tests early" approach suggest answers to
these?

David Malcolm (21):
  Selftest framework (unittests v5)
  Makefile.in integration
  Various selftest::runner tweaks.
  Add -fself-test-regex=
  Add selftests for diagnostic-show-locus.c
  Convert Levenshtein test from a plugin to a selftest
  Add selftests to bitmap.c
  Add selftests to tree-cfg.c
  Add selftests to et-forest.c
  Add selftests to fold-const.c
  Add function-tests.c
  Fix warning in function-tests.c
  Fixup to function-tests.c
  Remove x86_64-isms in function-tests.c
  Add selftests to gimple.c
  Add hash-map-tests.c
  Add hash-set-tests.c
  Add selftests to input.c
  Add rtl-tests.c
  Add selftests to tree.c
  Add selftests to vec.c

 gcc/Makefile.in                                  |  26 +-
 gcc/bitmap.c                                     |  92 ++++
 gcc/common.opt                                   |   8 +
 gcc/diagnostic-show-locus.c                      | 113 ++++
 gcc/et-forest.c                                  |  99 ++++
 gcc/fold-const.c                                 |  66 +++
 gcc/function-tests.c                             | 629 +++++++++++++++++++++++
 gcc/gimple.c                                     | 103 ++++
 gcc/hash-map-tests.c                             |  81 +++
 gcc/hash-set-tests.c                             |  57 ++
 gcc/input.c                                      | 110 ++++
 gcc/rtl-tests.c                                  |  98 ++++
 gcc/selftest.c                                   | 210 ++++++++
 gcc/selftest.h                                   | 267 ++++++++++
 gcc/spellcheck.c                                 |  48 ++
 gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c |   9 -
 gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c |  64 ---
 gcc/testsuite/gcc.dg/plugin/plugin.exp           |   1 -
 gcc/toplev.c                                     |  55 ++
 gcc/toplev.h                                     |   2 +
 gcc/tree-cfg.c                                   | 264 ++++++++++
 gcc/tree.c                                       |  47 ++
 gcc/vec.c                                        | 142 +++++
 23 files changed, 2512 insertions(+), 79 deletions(-)
 create mode 100644 gcc/function-tests.c
 create mode 100644 gcc/hash-map-tests.c
 create mode 100644 gcc/hash-set-tests.c
 create mode 100644 gcc/rtl-tests.c
 create mode 100644 gcc/selftest.c
 create mode 100644 gcc/selftest.h
 delete mode 100644 gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c
 delete mode 100644 gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c

-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 01/21] Selftest framework (unittests v5)
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
                                             ` (7 preceding siblings ...)
  2016-06-01 20:54                           ` [PATCH 18/21] Add selftests to input.c David Malcolm
@ 2016-06-01 20:54                           ` David Malcolm
  2016-06-01 20:54                           ` [PATCH 10/21] Add selftests to fold-const.c David Malcolm
                                             ` (13 subsequent siblings)
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 20:54 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

This is effectively v5 of the unittests proposal; for the earlier
versions see:
 * v1: https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00765.html
 * v2: https://gcc.gnu.org/ml/gcc-patches/2015-06/msg01224.html
 * v3: https://gcc.gnu.org/ml/gcc-patches/2015-10/msg02947.html
 * v4: https://gcc.gnu.org/ml/gcc-patches/2015-11/msg02379.html

New in v5:
  * eliminate RUN_ALL_TESTS macro
  * some bug fixes

Blurb from v4:

This patch adds a selftest.h/.c to gcc, with an API loosely
modelled on gtest (though without the use of CamelCase): it
supports enough of the gtest API to enable the tests that I
wrote to run with minimal changes.

It adds a -fself-test option, which runs the test at the end
of cc1,cc1plus, etc, similar to how the plugin worked in v2 and v3 of
the kit.

The tests themselves are in the followup patches.
I moved the tests from gcc/testsuite/unittests into gcc.  Where
possible, I moved the tests directly into the end of an
implementation file e.g. gcc/testsuite/unittests/test-vec.c became
an addition to gcc/vec.c; other files don't have a suitable .c file
e.g. for parametrized container types where there's just a .h, so
I created e.g. gcc/hash-map-tests.c

(Irritatingly, touching vec.c means that parts of the selftest code
become needed by e.g. collect2 so that vec.o can link; similarly for
input.o, which gains the location-handling selftests).

Everything apart from the -fself-test option itself is guarded
by #if CHECKING_P, so this all compiles away in a production
build to a "sorry, not supported".

Like gtest, tests are automatically discovered, using
some global object ctor magic.  Sadly this doesn't work
for some reason for source files which are purely tests, so
as a nasty workaround I #include those files from toplev.c

I didn't document -fself-test; should I?  (maybe just in the
internal docs?)

This iteration of the patchkit doesn't yet do anything to
automatically invoke -fself-test; I've been running it by hand
when compiling an empty .c file, so it's been running inside cc1.
How should this be hooked up?

Currently -fself-test requires an input file; should it?  (But if not,
what should the driver run?  All of them?).  Requiring an input file,
and providing an empty one may be simplest.

I anticipate a discussion about output formats; the current output
format is deliberately very verbose, to ensure that we're capturing
everything of interest.  It contains file/line info of each
EXPECT/ASSERT so that it's easy in Emacs to click in the compilation
buffer to go to specific assertions.

NOTE: bitmap_test.bitmap_single_bit_set_p: test starting
../../src/gcc/bitmap.c:2172: PASS: bitmap_test.bitmap_single_bit_set_p: EXPECT_FALSE (bitmap_single_bit_set_p (b))
../../src/gcc/bitmap.c:2175: PASS: bitmap_test.bitmap_single_bit_set_p: EXPECT_TRUE (bitmap_single_bit_set_p (b))
../../src/gcc/bitmap.c:2176: PASS: bitmap_test.bitmap_single_bit_set_p: EXPECT_EQ (42, bitmap_first_set_bit (b))
../../src/gcc/bitmap.c:2179: PASS: bitmap_test.bitmap_single_bit_set_p: EXPECT_FALSE (bitmap_single_bit_set_p (b))
../../src/gcc/bitmap.c:2180: PASS: bitmap_test.bitmap_single_bit_set_p: EXPECT_EQ (42, bitmap_first_set_bit (b))
../../src/gcc/bitmap.c:2183: PASS: bitmap_test.bitmap_single_bit_set_p: EXPECT_TRUE (bitmap_single_bit_set_p (b))
../../src/gcc/bitmap.c:2184: PASS: bitmap_test.bitmap_single_bit_set_p: EXPECT_EQ (1066, bitmap_first_set_bit (b))
NOTE: bitmap_test.bitmap_single_bit_set_p: test ending
NOTE: bitmap_test.clear_bit_in_middle: test starting
../../src/gcc/bitmap.c:2135: PASS: bitmap_test.clear_bit_in_middle: EXPECT_EQ (100, bitmap_count_bits (b))
../../src/gcc/bitmap.c:2139: PASS: bitmap_test.clear_bit_in_middle: EXPECT_TRUE (changed)
[...snip...]
NOTE: 491 pass(es); 0 failure(s)

Potentially we could have some kind of verbosity flag for the
selftests, I guess.

I did attempt to use "inform" to report results, but I don't think
this is appropriate for the most verbose form of output:
(A) some tests manipulate cfun and hence lead to strange
"In function ..." messages as they run based on the changes to cfun
(B) I want to write selftests for the diagnostics subsystem itself

I've successfully bootstrapped&regrtested the combination
of these patches on x86_64-pc-linux-gnu and manually
verified -fself-test (with the exception of the final
patch "RFC: Add ggc-tests.c" which has some issues, as noted
in that patch).

How does this look?

Notes on porting tests from gtest:
* Fixtures inherit from ::selftest::test, rather than
  from gtest's ::testing::Test
* There's no support yet for Setup and Teardown vfuncs (which
  presumably would be "setup" and "teardown")
* I only implemented what I needed
* I didn't implement type-parametrized testing, so for now
  I've dropped test-wide-int.c (which is the only test I had
  that was parametrized over multiple types).

gcc/ChangeLog:
	* Makefile.in (OBJS-libcommon): Add selftest.o.
	(OBJS-libcommon-target): Add selftest.o.
	(COLLECT2_OBJS): Add selftest.o.
	* common.opt (fself-test): New.
	* selftest.c: New file.
	* selftest.h: New file.
	* toplev.c: Include selftest.h.  Add includes of function-tests.c,
	hash-map-tests.c, hash-set-tests.c, rtl-tests.c as a workaround
	for a linker issue.
	(toplev::run_self_tests): New.
	(toplev::main): Handle -fself-test.
	* toplev.h (toplev::run_self_tests): New.
---
 gcc/Makefile.in |   7 +-
 gcc/common.opt  |   4 +
 gcc/selftest.c  | 152 ++++++++++++++++++++++++++++++++
 gcc/selftest.h  | 264 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/toplev.c    |  55 ++++++++++++
 gcc/toplev.h    |   2 +
 6 files changed, 481 insertions(+), 3 deletions(-)
 create mode 100644 gcc/selftest.c
 create mode 100644 gcc/selftest.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 673f87d..33dd75b 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1543,13 +1543,14 @@ OBJS = \
 # no target dependencies.
 OBJS-libcommon = diagnostic.o diagnostic-color.o diagnostic-show-locus.o \
 	pretty-print.o intl.o \
-	vec.o input.o version.o hash-table.o ggc-none.o memory-block.o
+	vec.o input.o version.o hash-table.o ggc-none.o memory-block.o \
+	selftest.o
 
 # Objects in libcommon-target.a, used by drivers and by the core
 # compiler and containing target-dependent code.
 OBJS-libcommon-target = $(common_out_object_file) prefix.o params.o \
 	opts.o opts-common.o options.o vec.o hooks.o common/common-targhooks.o \
-	hash-table.o file-find.o
+	hash-table.o file-find.o selftest.o
 
 # This lists all host objects for the front ends.
 ALL_HOST_FRONTEND_OBJS = $(foreach v,$(CONFIG_LANGUAGES),$($(v)_OBJS))
@@ -1986,7 +1987,7 @@ gcc-nm.c: gcc-ar.c
 	cp $^ $@
 
 COLLECT2_OBJS = collect2.o collect2-aix.o tlink.o vec.o ggc-none.o \
-  collect-utils.o file-find.o hash-table.o
+  collect-utils.o file-find.o hash-table.o selftest.o
 COLLECT2_LIBS = @COLLECT2_LIBS@
 collect2$(exeext): $(COLLECT2_OBJS) $(LIBDEPS)
 # Don't try modifying collect2 (aka ld) in place--it might be linking this.
diff --git a/gcc/common.opt b/gcc/common.opt
index 682cb41..95376bf 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2057,6 +2057,10 @@ fselective-scheduling2
 Common Report Var(flag_selective_scheduling2) Optimization
 Run selective scheduling after reload.
 
+fself-test
+Common Var(flag_self_test)
+Run self-tests.
+
 fsel-sched-pipelining
 Common Report Var(flag_sel_sched_pipelining) Init(0) Optimization
 Perform software pipelining of inner loops during selective scheduling.
diff --git a/gcc/selftest.c b/gcc/selftest.c
new file mode 100644
index 0000000..abb6585
--- /dev/null
+++ b/gcc/selftest.c
@@ -0,0 +1,152 @@
+/* A self-testing framework, for use by -fself-test.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+using namespace selftest;
+
+/* Helper function for ::selftest::run_all_tests.  */
+
+static int
+test_comparator (const void *p1, const void *p2)
+{
+  const test *t1 = *static_cast<const test * const *> (p1);
+  const test *t2 = *static_cast<const test * const *> (p2);
+  return strcmp (t1->get_name (), t2->get_name ());
+}
+
+/* Locate and run all tests.
+   Return the number of failures that occurred.  */
+
+int
+selftest::run_all_tests ()
+{
+  /* Create all the tests, in an arbitrary order (based on
+     the order of construction of the global "registrator" instances).  */
+  runner r;
+  auto_vec<test *> tests;
+  for (registrator *iter = registrator::get_first ();
+       iter;
+       iter = iter->get_next ())
+    {
+      test *t = iter->make (&r);
+      tests.safe_push (t);
+    }
+
+  /* Sort the tests into a predictable order.  */
+  tests.qsort (test_comparator);
+
+  /* Run all the tests, in order.  */
+  unsigned i;
+  test *t;
+  FOR_EACH_VEC_ELT (tests, i, t)
+    {
+      r.begin_test (t);
+      t->run ();
+      r.end_test (t);
+    }
+
+  /* Cleanup.  */
+  FOR_EACH_VEC_ELT (tests, i, t)
+    delete t;
+
+  return r.get_num_failures ();
+}
+
+/* Implementation of class ::selftest::runner.  */
+
+/* ::selftest::runner's constructor.  */
+
+runner::runner ()
+: m_passes (0),
+  m_failures (0)
+{
+}
+
+/* ::selftest::runner's destructor.  */
+
+runner::~runner ()
+{
+  fprintf (stderr, "NOTE: %i pass(es); %i failure(s)\n",
+	   m_passes, m_failures);
+}
+
+/* Notify the user that a particular test is about to be run.  */
+
+void
+runner::begin_test (test *t)
+{
+  fprintf (stderr, "NOTE: %s: test starting\n", t->get_name ());
+}
+
+/* Record and report the successful outcome of some aspect of a test.  */
+
+void
+runner::pass (const char *file, int line, test *t, const char *msg)
+{
+  fprintf (stderr, "%s:%i: PASS: %s: %s\n", file, line, t->get_name (), msg);
+  m_passes++;
+}
+
+/* Record and report the failed outcome of some aspect of a test.  */
+
+void
+runner::fail (const char *file, int line, test *t, const char *msg)
+{
+  fprintf (stderr, "%s:%i: FAIL: %s: %s\n", file, line, t->get_name (), msg);
+  m_failures++;
+}
+
+/* Notify the user that a particular test has finished running.  */
+
+void
+runner::end_test (test *t)
+{
+  fprintf (stderr, "NOTE: %s: test ending\n", t->get_name ());
+}
+
+/* Implementation of class ::selftest::registrator.  */
+
+/* This constructor is run before main; to avoid relying on
+   anything, it simply builds a singly-linked list of
+   instances.  */
+
+registrator::registrator (registrator::callback cb)
+: m_cb (cb), m_next (NULL)
+{
+  if (first)
+    {
+      /* Add this to the front of the list.  */
+      m_next = first;
+      first = this;
+    }
+  else
+    first = this;
+}
+
+/* The singleton head of the registrator linked list.  */
+
+registrator *registrator::first;
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest.h b/gcc/selftest.h
new file mode 100644
index 0000000..884bdbf
--- /dev/null
+++ b/gcc/selftest.h
@@ -0,0 +1,264 @@
+/* A self-testing framework, for use by -fself-test.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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/>.  */
+
+#ifndef GCC_SELFTEST_H
+#define GCC_SELFTEST_H
+
+/* The selftest code should entirely disappear in a production
+   configuration, hence we guard all of it with #if CHECKING_P.  */
+
+#if CHECKING_P
+
+namespace selftest {
+
+class test;
+class runner;
+class registrator;
+
+/* The entrypoint for running all tests.  */
+
+extern int run_all_tests ();
+
+/* The class ::selftest::runner is responsible for gathering results,
+   and for output.  */
+
+class runner
+{
+public:
+  runner ();
+  ~runner ();
+
+  void begin_test (test *t);
+  void pass (const char *file, int line, test *t, const char *msg);
+  void fail (const char *file, int line, test *t, const char *msg);
+  void end_test (test *t);
+
+  int get_num_failures () const { return m_failures; }
+
+private:
+  int m_passes;
+  int m_failures;
+};
+
+/* The class ::selftest::test is a base class from which specific
+   tests inherit, via the TEST and TEST_F macros below.  */
+
+class test
+{
+ public:
+  virtual ~test () {}
+  virtual void run () = 0;
+
+  const char *get_name () const { return m_name; }
+
+  void set_name (const char *name) { m_name = name; }
+  void set_runner (runner *r) { m_runner = r; }
+
+ protected:
+  void pass (const char *file, int line, const char *msg)
+  {
+    m_runner->pass (file, line, this, msg);
+  }
+  void fail (const char *file, int line, const char *msg)
+  {
+    m_runner->fail (file, line, this, msg);
+  }
+
+  /* We don't yet implement setup & teardown hooks.  */
+
+ private:
+  const char *m_name;
+  runner *m_runner;
+};
+
+/* An implementation detail of automatic test registration.
+   Global instances are created via the REGISTER_TEST below.
+   The constructor runs before main, wiring them up into a
+   singly-linked list, which can be traversed by
+   ::selftest::run_all_tests.  */
+
+class registrator
+{
+ public:
+  typedef test *(*callback) (runner *r);
+  registrator (callback cb);
+
+  static registrator *get_first () { return first; }
+  registrator *get_next () const { return m_next; }
+
+  test *make (runner *r) const { return m_cb (r); }
+
+ private:
+  callback m_cb;
+  registrator *m_next;
+  static registrator *first;
+};
+
+} /* end of namespace selftest.  */
+
+/* Macros for creating test functions.  */
+
+/* Define a new test, expecting a braced function body to follow.
+   The function body becomes the implementation of a "run" method of
+   a new ::selftest::test subclass, which will be instantiated and run
+   by RUN_ALL_TESTS.  */
+
+#define TEST(TEST_CASE_NAME, TEST_NAME)				\
+  IMPL_TEST_SUBCLASS (TEST_CASE_NAME ## _ ## TEST_NAME,		\
+		      ::selftest::test,				\
+		      (#TEST_CASE_NAME "." #TEST_NAME) )
+
+
+/* As per TEST above, but inheriting from a fixture subclass, rather
+   than directly from ::selftest::test.  */
+
+#define TEST_F(FIXTURE_CLASS_NAME, TEST_NAME)		    \
+  IMPL_TEST_SUBCLASS (FIXTURE_CLASS_NAME ## _ ## TEST_NAME, \
+		      FIXTURE_CLASS_NAME,		    \
+		      (#FIXTURE_CLASS_NAME "." #TEST_NAME) )
+
+/* Macros for writing tests.  */
+
+/* Evaluate EXPR and coerce to bool, issuing PASS if it is true,
+   FAIL if it false.  */
+
+#define EXPECT_TRUE(EXPR)				\
+  SELFTEST_BEGIN_STMT					\
+  const char *desc = "EXPECT_TRUE (" #EXPR ")";	\
+  bool actual = (EXPR);				\
+  if (actual)						\
+    pass (__FILE__, __LINE__, desc);			\
+  else							\
+    fail (__FILE__, __LINE__, desc);			\
+  SELFTEST_END_STMT
+
+/* Evaluate EXPR and coerce to bool, issuing PASS if it is false,
+   FAIL if it true.  */
+
+#define EXPECT_FALSE(EXPR)					\
+  SELFTEST_BEGIN_STMT						\
+  const char *desc = "EXPECT_FALSE (" #EXPR ")";		\
+  bool actual = (EXPR);					\
+  if (actual)							\
+    fail (__FILE__, __LINE__, desc);				\
+  else								\
+    pass (__FILE__, __LINE__, desc);				\
+  SELFTEST_END_STMT
+
+/* Evaluate EXPECTED and ACTUAL and compare them with ==, issuing PASS
+   if they are equal, FAIL if they are non-equal.  */
+
+#define EXPECT_EQ(EXPECTED, ACTUAL)			       \
+  SELFTEST_BEGIN_STMT					       \
+  const char *desc = "EXPECT_EQ (" #EXPECTED ", " #ACTUAL ")"; \
+  if ((EXPECTED) == (ACTUAL))				       \
+    pass (__FILE__, __LINE__, desc);			       \
+  else							       \
+    fail (__FILE__, __LINE__, desc);			       \
+  SELFTEST_END_STMT
+
+/* Evaluate EXPECTED and ACTUAL and compare them with !=, issuing PASS
+   if they are non-equal, FAIL if they are equal.  */
+
+#define EXPECT_NE(EXPECTED, ACTUAL)			       \
+  SELFTEST_BEGIN_STMT					       \
+  const char *desc = "EXPECT_NE (" #EXPECTED ", " #ACTUAL ")"; \
+  if ((EXPECTED) != (ACTUAL))				       \
+    pass (__FILE__, __LINE__, desc);			       \
+  else							       \
+    fail (__FILE__, __LINE__, desc);			       \
+  SELFTEST_END_STMT
+
+/* Evaluate EXPECTED and ACTUAL and compare them with strcmp, issuing
+   PASS if they are equal, FAIL if they are non-equal.  */
+
+#define EXPECT_STREQ(EXPECTED, ACTUAL)			       \
+  SELFTEST_BEGIN_STMT					       \
+  const char *desc = "EXPECT_STREQ (" #EXPECTED ", " #ACTUAL ")"; \
+  const char *expected_ = (EXPECTED);				  \
+  const char *actual_ = (ACTUAL);				  \
+  if (0 == strcmp (expected_, actual_))				  \
+    pass (__FILE__, __LINE__, desc);			       \
+  else							       \
+    fail (__FILE__, __LINE__, desc);			       \
+  SELFTEST_END_STMT
+
+/* Evaluate PRED1 (VAL1), issuing PASS if it is true, FAIL if
+   it false.  */
+
+#define EXPECT_PRED1(PRED1, VAL1)			\
+  SELFTEST_BEGIN_STMT					\
+  const char *desc = "EXPECT_PRED1 (" #PRED1 ", " #VAL1 ")";	\
+  bool actual = (PRED1) (VAL1);				\
+  if (actual)						\
+    pass (__FILE__, __LINE__, desc);			\
+  else							\
+    fail (__FILE__, __LINE__, desc);			\
+  SELFTEST_END_STMT
+
+/* As per EXPECT_TRUE, but immediately end the test (via return) if
+   if fails.  */
+
+#define ASSERT_TRUE(EXPR)				\
+  SELFTEST_BEGIN_STMT					\
+  const char *desc = "ASSERT_TRUE (" #EXPR ")";	\
+  bool actual = (EXPR);				\
+  if (actual)						\
+    pass (__FILE__, __LINE__, desc);			\
+  else							\
+    {							\
+      fail (__FILE__, __LINE__, desc);			\
+      return;						\
+    }							\
+  SELFTEST_END_STMT
+
+/* The remaining macros are implementation details, for internal use.  */
+
+/* A macro for registering a test subclass, by creating a global object
+   with a non-trivial ctor.  */
+
+#define REGISTER_TEST(SUBCLASSNAME) \
+  static selftest::registrator registrator_for_ ##SUBCLASSNAME(&SUBCLASSNAME::make)
+
+/* This macro is used to implement TEST and TEST_F.  It creates a new
+   subclass of ::selftest::test, and begins the definition of a "run"
+   method for the subclass, expecting a braced method body to follow.  */
+
+#define IMPL_TEST_SUBCLASS(SUBCLASS_NAME, BASE_CLASS, NAME)		\
+  class SUBCLASS_NAME : public BASE_CLASS				\
+  {									\
+  public:								\
+    void run ();							\
+    static ::selftest::test *make (::selftest::runner *r)		\
+    {									\
+      ::selftest::test *t = new SUBCLASS_NAME ();			\
+      t->set_name (NAME);						\
+      t->set_runner (r);						\
+      return t;							\
+    }									\
+  };									\
+  REGISTER_TEST(SUBCLASS_NAME);					\
+  void SUBCLASS_NAME::run ()
+
+#define SELFTEST_BEGIN_STMT do {
+#define SELFTEST_END_STMT   } while (0)
+
+#endif /* #if CHECKING_P */
+
+#endif /* GCC_SELFTEST_H */
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 580c03a..74712e5 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -87,6 +87,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "xcoffout.h"		/* Needed for external data declarations. */
 #endif
 
+#include "selftest.h"
+
+#include <new>
+
 static void general_init (const char *, bool);
 static void do_compile ();
 static void process_options (void);
@@ -2031,6 +2035,54 @@ toplev::start_timevars ()
   timevar_start (TV_TOTAL);
 }
 
+/* For some tests, there's a natural source file to place them in.
+   For others, they can live in their own "foo-tests.c" file.
+   Ideally, these "foo-tests.c" files would be added to OBJS in
+   Makefile.in.
+   Unfortunately, due to this bug in GNU ld
+      https://sourceware.org/bugzilla/show_bug.cgi?id=20152
+   such tests don't get run if they are linked into libbackend.a;
+   the linker appears to be discarding the global "registrator"
+   instances in files which are purely test cases.  It appears
+   to work if the .o files are linked directly into cc1 (rather
+   than via libbackend.a).
+
+   Hence as a workaround, we instead directly include the files here.  */
+
+#if CHECKING_P
+
+#include "function-tests.c"
+#include "hash-map-tests.c"
+#include "hash-set-tests.c"
+#include "rtl-tests.c"
+
+#endif /* #if CHECKING_P */
+
+/* Handle -fself-test.   */
+
+void
+toplev::run_self_tests ()
+{
+#if CHECKING_P
+  /* Reset some state.  */
+  input_location = UNKNOWN_LOCATION;
+  bitmap_obstack_initialize (NULL);
+
+  /* Run the tests.  */
+  int result = ::selftest::run_all_tests ();
+
+  /* Ensure that a test failure leads to the process exiting with
+     a non-zero exit code.  */
+  if (result)
+    error ("at least one test failure occurred");
+
+  /* Cleanup.  */
+  bitmap_obstack_release (NULL);
+#else
+  sorry ("self-tests are not enabled in this build");
+#endif /* #if CHECKING_P */
+}
+
 /* Entry point of cc1, cc1plus, jc1, f771, etc.
    Exit code is FATAL_EXIT_CODE if can't open files or if there were
    any errors, or SUCCESS_EXIT_CODE if compilation succeeded.
@@ -2098,6 +2150,9 @@ toplev::main (int argc, char **argv)
   if (warningcount || errorcount || werrorcount)
     print_ignored_options ();
 
+  if (flag_self_test)
+    run_self_tests ();
+
   /* Invoke registered plugin callbacks if any.  Some plugins could
      emit some diagnostics here.  */
   invoke_plugin_callbacks (PLUGIN_FINISH, NULL);
diff --git a/gcc/toplev.h b/gcc/toplev.h
index 0beb06e..06923cf 100644
--- a/gcc/toplev.h
+++ b/gcc/toplev.h
@@ -42,6 +42,8 @@ private:
 
   void start_timevars ();
 
+  void run_self_tests ();
+
   bool m_use_TV_TOTAL;
   bool m_init_signals;
 };
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 09/21] Add selftests to et-forest.c
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
  2016-06-01 20:54                           ` [PATCH 07/21] Add selftests to bitmap.c David Malcolm
  2016-06-01 20:54                           ` [PATCH 04/21] Add -fself-test-regex= David Malcolm
@ 2016-06-01 20:54                           ` David Malcolm
  2016-06-01 20:54                           ` [PATCH 03/21] Various selftest::runner tweaks David Malcolm
                                             ` (19 subsequent siblings)
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 20:54 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this:
  https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03295.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files
> is pre-approved.

gcc/ChangeLog:
	* et-forest.c: Include "selftest.h".
	(et_forest_test, single_node): New selftest.
	(et_forest_test, simple_tree): New selftest.
---
 gcc/et-forest.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 99 insertions(+)

diff --git a/gcc/et-forest.c b/gcc/et-forest.c
index cd36752..9a65e9d 100644
--- a/gcc/et-forest.c
+++ b/gcc/et-forest.c
@@ -27,6 +27,7 @@ License along with libiberty; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "alloc-pool.h"
 #include "et-forest.h"
+#include "selftest.h"
 
 /* We do not enable this with CHECKING_P, since it is awfully slow.  */
 #undef DEBUG_ET
@@ -764,3 +765,101 @@ et_root (struct et_node *node)
 
   return r->of;
 }
+
+#if CHECKING_P
+
+namespace {
+
+TEST (et_forest_test, single_node)
+{
+  void *test_data = (void *)0xcafebabe;
+
+  et_node *n = et_new_tree (test_data);
+  EXPECT_EQ (n->data, test_data);
+  EXPECT_EQ (n, et_root (n));
+  et_free_tree (n);
+}
+
+/* Test of this tree:
+       a
+      / \
+     /   \
+    b     c
+   / \    |
+  d   e   f.  */
+
+TEST (et_forest_test, simple_tree)
+{
+  et_node *a = et_new_tree (NULL);
+  et_node *b = et_new_tree (NULL);
+  et_node *c = et_new_tree (NULL);
+  et_node *d = et_new_tree (NULL);
+  et_node *e = et_new_tree (NULL);
+  et_node *f = et_new_tree (NULL);
+
+  et_set_father (b, a);
+  et_set_father (c, a);
+  et_set_father (d, b);
+  et_set_father (e, b);
+  et_set_father (f, c);
+
+  EXPECT_TRUE (et_below (a, a));
+  EXPECT_TRUE (et_below (b, a));
+  EXPECT_TRUE (et_below (c, a));
+  EXPECT_TRUE (et_below (d, a));
+  EXPECT_TRUE (et_below (e, a));
+  EXPECT_TRUE (et_below (f, a));
+
+  EXPECT_FALSE (et_below (a, b));
+  EXPECT_TRUE (et_below (b, b));
+  EXPECT_FALSE (et_below (c, b));
+  EXPECT_TRUE (et_below (d, b));
+  EXPECT_TRUE (et_below (e, b));
+  EXPECT_FALSE (et_below (f, b));
+
+  EXPECT_FALSE (et_below (a, c));
+  EXPECT_FALSE (et_below (b, c));
+  EXPECT_TRUE (et_below (c, c));
+  EXPECT_FALSE (et_below (d, c));
+  EXPECT_FALSE (et_below (e, c));
+  EXPECT_TRUE (et_below (f, c));
+
+  EXPECT_FALSE (et_below (a, d));
+  EXPECT_FALSE (et_below (b, d));
+  EXPECT_FALSE (et_below (c, d));
+  EXPECT_TRUE (et_below (d, d));
+  EXPECT_FALSE (et_below (e, d));
+  EXPECT_FALSE (et_below (f, d));
+
+  EXPECT_FALSE (et_below (a, e));
+  EXPECT_FALSE (et_below (b, e));
+  EXPECT_FALSE (et_below (c, e));
+  EXPECT_FALSE (et_below (d, e));
+  EXPECT_TRUE (et_below (e, e));
+  EXPECT_FALSE (et_below (f, e));
+
+  EXPECT_FALSE (et_below (a, f));
+  EXPECT_FALSE (et_below (b, f));
+  EXPECT_FALSE (et_below (c, f));
+  EXPECT_FALSE (et_below (d, f));
+  EXPECT_FALSE (et_below (e, f));
+  EXPECT_TRUE (et_below (f, f));
+
+  et_free_tree_force (a);
+}
+
+TEST (et_forest_test, disconnected_nodes)
+{
+  et_node *a = et_new_tree (NULL);
+  et_node *b = et_new_tree (NULL);
+
+  EXPECT_FALSE (et_below (a, b));
+  EXPECT_FALSE (et_below (b, a));
+
+  et_free_tree (a);
+  et_free_tree (b);
+}
+
+}  // anon namespace
+
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 17/21] Add hash-set-tests.c
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
                                             ` (4 preceding siblings ...)
  2016-06-01 20:54                           ` [PATCH 02/21] Makefile.in integration David Malcolm
@ 2016-06-01 20:54                           ` David Malcolm
  2016-06-01 20:54                           ` [PATCH 20/21] Add selftests to tree.c David Malcolm
                                             ` (16 subsequent siblings)
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 20:54 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-hash-set.c):
 https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03300.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files is
> pre-approved.

This version moves the tests to gcc/hash-set-tests.c.

gcc/ChangeLog:
	* hash-set-tests.c: New file.
---
 gcc/hash-set-tests.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 gcc/hash-set-tests.c

diff --git a/gcc/hash-set-tests.c b/gcc/hash-set-tests.c
new file mode 100644
index 0000000..8582663
--- /dev/null
+++ b/gcc/hash-set-tests.c
@@ -0,0 +1,57 @@
+/* Unit tests for hash-set.h.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+namespace {
+
+TEST (hash_set_test, set_of_strings)
+{
+  hash_set <const char *> s;
+  EXPECT_EQ (0, s.elements ());
+
+  const char *red = "red";
+  const char *green = "green";
+  const char *blue = "blue";
+
+  EXPECT_EQ (false, s.contains (red));
+
+  /* Populate the hash_set.  */
+  EXPECT_EQ (false, s.add (red));
+  EXPECT_EQ (false, s.add (green));
+  EXPECT_EQ (false, s.add (blue));
+
+  /* Verify that the values are now within the set.  */
+  EXPECT_EQ (true, s.contains (red));
+  EXPECT_EQ (true, s.contains (green));
+  EXPECT_EQ (true, s.contains (blue));
+}
+
+}  /* anon namespace.  */
+
+#endif /* #if CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 12/21] Fix warning in function-tests.c
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
                                             ` (9 preceding siblings ...)
  2016-06-01 20:54                           ` [PATCH 10/21] Add selftests to fold-const.c David Malcolm
@ 2016-06-01 21:09                           ` David Malcolm
  2016-06-01 21:10                           ` [PATCH 21/21] Add selftests to vec.c David Malcolm
                                             ` (11 subsequent siblings)
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 21:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Upon porting from gtest.h to selftest.h I ran into this warning which
is fatal during bootstrap:

In file included from ../../../src/gcc/toplev.c:89:0:
../../../src/gcc/function-tests.c: In member function ‘virtual void {anonymous}::function_test_fndecl_int_void::run()’:
../../../src/gcc/selftest.h:182:28: error: comparison with string literal results in unspecified behaviour [-Werror=address]
   if ((EXPECTED) != (ACTUAL))           \
                            ^

../../../src/gcc/function-tests.c:125:3: note: in expansion of macro ‘EXPECT_NE’
   EXPECT_NE ("test_fndecl_int_void", identifier_ptr);
   ^~~~~~~~~

../../../src/gcc/function-tests.c: In member function ‘virtual void {anonymous}::function_test_fndecl_float_intchar::run()’:
../../../src/gcc/selftest.h:182:28: error: comparison with string literal results in unspecified behaviour [-Werror=address]
   if ((EXPECTED) != (ACTUAL))           \
                            ^

../../../src/gcc/function-tests.c:159:3: note: in expansion of macro ‘EXPECT_NE’
   EXPECT_NE ("test_fndecl_float_intchar", identifier_ptr);
   ^~~~~~~~~

This patch fixes the warning.

gcc/ChangeLog:
	* function-tests.c (function_test, fndecl_int_void):
	Introduce local "name" to avoid a "comparison with string literal"
	warning.
	(function_test, fndecl_float_intchar): Likewise.
---
 gcc/function-tests.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/gcc/function-tests.c b/gcc/function-tests.c
index 58b27b8..db105bf 100644
--- a/gcc/function-tests.c
+++ b/gcc/function-tests.c
@@ -111,8 +111,9 @@ class function_test : public ::selftest::test
 TEST_F (function_test, fndecl_int_void)
 {
   auto_vec <tree> param_types;
+  const char *name = "test_fndecl_int_void";
   tree fndecl = make_fndecl (integer_type_node,
-			     "test_fndecl_int_void",
+			     name,
 			     param_types);
   ASSERT_TRUE (fndecl != NULL);
 
@@ -122,7 +123,7 @@ TEST_F (function_test, fndecl_int_void)
   EXPECT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
   /* We expect it to use a *copy* of the string we passed in.  */
   const char *identifier_ptr = IDENTIFIER_POINTER (declname);
-  EXPECT_NE ("test_fndecl_int_void", identifier_ptr);
+  EXPECT_NE (name, identifier_ptr);
   EXPECT_EQ (0, strcmp ("test_fndecl_int_void", identifier_ptr));
 
   /* Verify type of fndecl.  */
@@ -145,8 +146,9 @@ TEST_F (function_test, fndecl_float_intchar)
   auto_vec <tree> param_types;
   param_types.safe_push (integer_type_node);
   param_types.safe_push (char_type_node);
+  const char *name = "test_fndecl_float_intchar";
   tree fndecl = make_fndecl (float_type_node,
-			     "test_fndecl_float_intchar",
+			     name,
 			     param_types);
   ASSERT_TRUE (fndecl != NULL);
 
@@ -156,8 +158,8 @@ TEST_F (function_test, fndecl_float_intchar)
   EXPECT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
   /* We expect it to use a *copy* of the string we passed in.  */
   const char *identifier_ptr = IDENTIFIER_POINTER (declname);
-  EXPECT_NE ("test_fndecl_float_intchar", identifier_ptr);
-  EXPECT_EQ (0, strcmp ("test_fndecl_float_intchar", identifier_ptr));
+  EXPECT_NE (name, identifier_ptr);
+  EXPECT_EQ (0, strcmp (name, identifier_ptr));
 
   /* Verify type of fndecl.  */
   EXPECT_EQ (FUNCTION_DECL, TREE_CODE (fndecl));
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 06/21] Convert Levenshtein test from a plugin to a selftest
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
                                             ` (11 preceding siblings ...)
  2016-06-01 21:10                           ` [PATCH 21/21] Add selftests to vec.c David Malcolm
@ 2016-06-01 21:10                           ` David Malcolm
  2016-06-01 21:10                           ` [PATCH 08/21] Add selftests to tree-cfg.c David Malcolm
                                             ` (9 subsequent siblings)
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 21:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

This is an example of converting one of our existing plugin-based
tests to run within -fself-test instead.

gcc/ChangeLog:
	* spellcheck.c: Include "selftest.h".
	(spellcheck_test): New class
	(TEST_F (spellcheck_test, levenshtein_distance)): New selftest,
	based on testsuite/gcc.dg/plugin/levenshtein_plugin.c.

gcc/testsuite/ChangeLog:
	* gcc.dg/plugin/levenshtein-test-1.c: Delete.
	* gcc.dg/plugin/levenshtein_plugin.c: Delete.
	* gcc.dg/plugin/plugin.exp (plugin_test_list): Remove the
	above.
---
 gcc/spellcheck.c                                 | 48 ++++++++++++++++++
 gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c |  9 ----
 gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c | 64 ------------------------
 gcc/testsuite/gcc.dg/plugin/plugin.exp           |  1 -
 4 files changed, 48 insertions(+), 74 deletions(-)
 delete mode 100644 gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c
 delete mode 100644 gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c

diff --git a/gcc/spellcheck.c b/gcc/spellcheck.c
index e4e83a5..12ff13b 100644
--- a/gcc/spellcheck.c
+++ b/gcc/spellcheck.c
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "tree.h"
 #include "spellcheck.h"
+#include "selftest.h"
 
 /* The Levenshtein distance is an "edit-distance": the minimal
    number of one-character insertions, removals or substitutions
@@ -165,3 +166,50 @@ find_closest_string (const char *target,
 
   return best_candidate;
 }
+
+#if CHECKING_P
+
+namespace {
+
+class spellcheck_test : public ::selftest::test
+{
+ protected:
+  void
+  levenshtein_distance_unit_test_oneway (const char *a, const char *b,
+					 edit_distance_t expected)
+  {
+    edit_distance_t actual = levenshtein_distance (a, b);
+    EXPECT_EQ (actual, expected);
+  }
+
+  void
+  levenshtein_distance_unit_test (const char *a, const char *b,
+				  edit_distance_t expected)
+  {
+    /* Run every test both ways to ensure it's symmetric.  */
+    levenshtein_distance_unit_test_oneway (a, b, expected);
+    levenshtein_distance_unit_test_oneway (b, a, expected);
+  }
+};
+
+TEST_F (spellcheck_test, levenshtein_distance)
+{
+  levenshtein_distance_unit_test ("", "nonempty", strlen ("nonempty"));
+  levenshtein_distance_unit_test ("saturday", "sunday", 3);
+  levenshtein_distance_unit_test ("foo", "m_foo", 2);
+  levenshtein_distance_unit_test ("hello_world", "HelloWorld", 3);
+  levenshtein_distance_unit_test
+    ("the quick brown fox jumps over the lazy dog", "dog", 40);
+  levenshtein_distance_unit_test
+    ("the quick brown fox jumps over the lazy dog",
+     "the quick brown dog jumps over the lazy fox",
+     4);
+  levenshtein_distance_unit_test
+    ("Lorem ipsum dolor sit amet, consectetur adipiscing elit,",
+     "All your base are belong to us",
+     44);
+}
+
+}  /* anon namespace.  */
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c b/gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c
deleted file mode 100644
index ac49992..0000000
--- a/gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c
+++ /dev/null
@@ -1,9 +0,0 @@
-/* Placeholder C source file for unit-testing gcc/spellcheck.c.  */
-/* { dg-do compile } */
-/* { dg-options "-O" } */
-
-int
-main (int argc, char **argv)
-{
-  return 0;
-}
diff --git a/gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c b/gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c
deleted file mode 100644
index 3e7dc78..0000000
--- a/gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Plugin for unittesting gcc/spellcheck.h.  */
-
-#include "config.h"
-#include "gcc-plugin.h"
-#include "system.h"
-#include "coretypes.h"
-#include "spellcheck.h"
-#include "diagnostic.h"
-
-int plugin_is_GPL_compatible;
-
-static void
-levenshtein_distance_unit_test_oneway (const char *a, const char *b,
-				       edit_distance_t expected)
-{
-  edit_distance_t actual = levenshtein_distance (a, b);
-  if (actual != expected)
-    error ("levenshtein_distance (\"%s\", \"%s\") : expected: %i got %i",
-	   a, b, expected, actual);
-}
-
-
-static void
-levenshtein_distance_unit_test (const char *a, const char *b,
-				edit_distance_t expected)
-{
-  /* Run every test both ways to ensure it's symmetric.  */
-  levenshtein_distance_unit_test_oneway (a, b, expected);
-  levenshtein_distance_unit_test_oneway (b, a, expected);
-}
-
-/* Callback handler for the PLUGIN_FINISH event; run
-   levenshtein_distance unit tests here.  */
-
-static void
-on_finish (void */*gcc_data*/, void */*user_data*/)
-{
-  levenshtein_distance_unit_test ("", "nonempty", strlen ("nonempty"));
-  levenshtein_distance_unit_test ("saturday", "sunday", 3);
-  levenshtein_distance_unit_test ("foo", "m_foo", 2);
-  levenshtein_distance_unit_test ("hello_world", "HelloWorld", 3);
-  levenshtein_distance_unit_test
-    ("the quick brown fox jumps over the lazy dog", "dog", 40);
-  levenshtein_distance_unit_test
-    ("the quick brown fox jumps over the lazy dog",
-     "the quick brown dog jumps over the lazy fox",
-     4);
-  levenshtein_distance_unit_test
-    ("Lorem ipsum dolor sit amet, consectetur adipiscing elit,",
-     "All your base are belong to us",
-     44);
-}
-
-int
-plugin_init (struct plugin_name_args *plugin_info,
-	     struct plugin_gcc_version */*version*/)
-{
-  register_callback (plugin_info->base_name,
-		     PLUGIN_FINISH,
-		     on_finish,
-		     NULL); /* void *user_data */
-
-  return 0;
-}
diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp
index fd1e98e..dfcdea2 100644
--- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
+++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
@@ -70,7 +70,6 @@ set plugin_test_list [list \
 	  diagnostic-test-expressions-1.c } \
     { diagnostic_plugin_show_trees.c \
 	  diagnostic-test-show-trees-1.c } \
-    { levenshtein_plugin.c levenshtein-test-1.c } \
     { location_overflow_plugin.c \
 	  location-overflow-test-1.c \
 	  location-overflow-test-2.c } \
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 21/21] Add selftests to vec.c
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
                                             ` (10 preceding siblings ...)
  2016-06-01 21:09                           ` [PATCH 12/21] Fix warning in function-tests.c David Malcolm
@ 2016-06-01 21:10                           ` David Malcolm
  2016-06-01 21:10                           ` [PATCH 06/21] Convert Levenshtein test from a plugin to a selftest David Malcolm
                                             ` (10 subsequent siblings)
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 21:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-vec.c):
 https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03308.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files is
> pre-approved.

This version puts the tests at the end of vec.c.

gcc/ChangeLog:
	* vec.c: Include "selftest.h".
	(class vec_test): New test subclass.
	(vec_test, quick_push): New selftest.
	(vec_test, safe_push): New selftest.
	(vec_test, truncate): New selftest.
	(vec_test, safe_grow_cleared): New selftest.
	(vec_test, pop): New selftest.
	(vec_test, safe_insert): New selftest.
	(vec_test, ordered_remove): New selftest.
	(vec_test, unordered_remove): New selftest.
	(vec_test, block_remove): New selftest.
	(reverse_cmp): New function.
	(vec_test, qsort): New selftest.
---
 gcc/vec.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 142 insertions(+)

diff --git a/gcc/vec.c b/gcc/vec.c
index a483d5b..20fed31 100644
--- a/gcc/vec.c
+++ b/gcc/vec.c
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "hash-table.h"
+#include "selftest.h"
 
 /* vNULL is an empty type with a template cast operation that returns
    a zero-initialized vec<T, A, L> instance.  Use this when you want
@@ -188,3 +189,144 @@ dump_vec_loc_statistics (void)
 {
   vec_mem_desc.dump (VEC_ORIGIN);
 }
+
+#ifndef GENERATOR_FILE
+#if CHECKING_P
+
+namespace {
+
+class vec_test : public ::selftest::test
+{
+ protected:
+  /* Add the range [START..LIMIT) to V.  */
+  void
+  safe_push_range (vec <int>&v, int start, int limit)
+  {
+    for (int i = start; i < limit; i++)
+      v.safe_push (i);
+  }
+};
+
+TEST_F (vec_test, quick_push)
+{
+  auto_vec <int> v;
+  EXPECT_EQ (0, v.length ());
+  v.reserve (3);
+  EXPECT_EQ (0, v.length ());
+  EXPECT_TRUE (v.space (3));
+  v.quick_push (5);
+  v.quick_push (6);
+  v.quick_push (7);
+  EXPECT_EQ (3, v.length ());
+  EXPECT_EQ (5, v[0]);
+  EXPECT_EQ (6, v[1]);
+  EXPECT_EQ (7, v[2]);
+}
+
+TEST_F (vec_test, safe_push)
+{
+  auto_vec <int> v;
+  EXPECT_EQ (0, v.length ());
+  v.safe_push (5);
+  v.safe_push (6);
+  v.safe_push (7);
+  EXPECT_EQ (3, v.length ());
+  EXPECT_EQ (5, v[0]);
+  EXPECT_EQ (6, v[1]);
+  EXPECT_EQ (7, v[2]);
+}
+
+TEST_F (vec_test, truncate)
+{
+  auto_vec <int> v;
+  EXPECT_EQ (0, v.length ());
+  safe_push_range (v, 0, 10);
+  EXPECT_EQ (10, v.length ());
+
+  v.truncate (5);
+  EXPECT_EQ (5, v.length ());
+}
+
+TEST_F (vec_test, safe_grow_cleared)
+{
+  auto_vec <int> v;
+  EXPECT_EQ (0, v.length ());
+  v.safe_grow_cleared (50);
+  EXPECT_EQ (50, v.length ());
+  EXPECT_EQ (0, v[0]);
+  EXPECT_EQ (0, v[49]);
+}
+
+TEST_F (vec_test, pop)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 5, 20);
+  EXPECT_EQ (15, v.length ());
+
+  int last = v.pop ();
+  EXPECT_EQ (19, last);
+  EXPECT_EQ (14, v.length ());
+}
+
+TEST_F (vec_test, safe_insert)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.safe_insert (5, 42);
+  EXPECT_EQ (4, v[4]);
+  EXPECT_EQ (42, v[5]);
+  EXPECT_EQ (5, v[6]);
+  EXPECT_EQ (11, v.length ());
+}
+
+TEST_F (vec_test, ordered_remove)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.ordered_remove (5);
+  EXPECT_EQ (4, v[4]);
+  EXPECT_EQ (6, v[5]);
+  EXPECT_EQ (9, v.length ());
+}
+
+TEST_F (vec_test, unordered_remove)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.unordered_remove (5);
+  EXPECT_EQ (9, v.length ());
+}
+
+TEST_F (vec_test, block_remove)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.block_remove (5, 3);
+  EXPECT_EQ (3, v[3]);
+  EXPECT_EQ (4, v[4]);
+  EXPECT_EQ (8, v[5]);
+  EXPECT_EQ (9, v[6]);
+  EXPECT_EQ (7, v.length ());
+}
+
+static int reverse_cmp (const void *p_i, const void *p_j)
+{
+  return *(const int *)p_j - *(const int *)p_i;
+}
+
+TEST_F (vec_test, qsort)
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.qsort (reverse_cmp);
+  EXPECT_EQ (9, v[0]);
+  EXPECT_EQ (8, v[1]);
+  EXPECT_EQ (1, v[8]);
+  EXPECT_EQ (0, v[9]);
+  EXPECT_EQ (10, v.length ());
+}
+
+}  // anon namespace
+
+#endif /* #if CHECKING_P */
+#endif /* #ifndef GENERATOR_FILE */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 08/21] Add selftests to tree-cfg.c
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
                                             ` (12 preceding siblings ...)
  2016-06-01 21:10                           ` [PATCH 06/21] Convert Levenshtein test from a plugin to a selftest David Malcolm
@ 2016-06-01 21:10                           ` David Malcolm
  2016-06-01 21:10                           ` [PATCH 11/21] Add function-tests.c David Malcolm
                                             ` (8 subsequent siblings)
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 21:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an older version of this:
  https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03285.html
with:
> Unless there's a good reason, drop the presumably redundant tests
> and this is OK. Save preapprovald for these changes as the bitmap
> patch.

This version removes the redundant tests, and moves the tests
from being in a new file to being in tree-cfg.c

gcc/ChangeLog:
	* tree-cfg.c: Include "selftest.h".
	(class cfg_test): New test subclass.
	(cfg_test, linear_chain): New selftest.
	(cfg_test, diamond): New selftest.
	(cfg_test, fully_connected): New selftest.
---
 gcc/tree-cfg.c | 264 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 264 insertions(+)

diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 6573702..ff5b1e0 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -58,6 +58,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-cfgcleanup.h"
 #include "gimplify.h"
 #include "attribs.h"
+#include "selftest.h"
 
 /* This file contains functions for building the Control Flow Graph (CFG)
    for a function tree.  */
@@ -9145,3 +9146,266 @@ gt_pch_nx (edge_def *e, gt_pointer_operator op, void *cookie)
     op (&(e->insns.r), cookie);
   op (&(block), cookie);
 }
+
+#if CHECKING_P
+
+namespace {
+
+class cfg_test : public ::selftest::test
+{
+ protected:
+  tree
+  push_fndecl (const char *name)
+  {
+    tree fn_type = build_function_type_array (integer_type_node, /* return_type */
+					    0, NULL);
+    /* FIXME: this uses input_location: */
+    tree fndecl = build_fn_decl (name, fn_type);
+    tree retval = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+			      NULL_TREE, integer_type_node);
+    DECL_RESULT (fndecl) = retval;
+    push_struct_function (fndecl);
+    function *fun = DECL_STRUCT_FUNCTION (fndecl);
+    EXPECT_TRUE (fun != NULL);
+    init_empty_tree_cfg_for_function (fun);
+    EXPECT_EQ (2, n_basic_blocks_for_fn (fun));
+    EXPECT_EQ (0, n_edges_for_fn (fun));
+    return fndecl;
+  }
+};
+
+/* These tests directly create CFGs.
+   Compare with the static fns within tree-cfg.c:
+     - build_gimple_cfg
+     - make_blocks: calls create_basic_block (seq, bb);
+     - make_edges.   */
+
+/* Verify a simple cfg of the form:
+     ENTRY -> A -> B -> C -> EXIT.  */
+TEST_F (cfg_test, linear_chain)
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_test_linear_chain");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+
+  /* Create some empty blocks.  */
+  basic_block bb_a = create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun));
+  basic_block bb_b = create_empty_bb (bb_a);
+  basic_block bb_c = create_empty_bb (bb_b);
+
+  EXPECT_EQ (5, n_basic_blocks_for_fn (fun));
+  EXPECT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create some edges: a simple linear chain of BBs.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), bb_a, EDGE_FALLTHRU);
+  make_edge (bb_a, bb_b, 0);
+  make_edge (bb_b, bb_c, 0);
+  make_edge (bb_c, EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+
+  /* Verify the edges.  */
+  EXPECT_EQ (4, n_edges_for_fn (fun));
+  EXPECT_EQ (NULL, ENTRY_BLOCK_PTR_FOR_FN (fun)->preds);
+  EXPECT_EQ (1, ENTRY_BLOCK_PTR_FOR_FN (fun)->succs->length ());
+  EXPECT_EQ (1, bb_a->preds->length ());
+  EXPECT_EQ (1, bb_a->succs->length ());
+  EXPECT_EQ (1, bb_b->preds->length ());
+  EXPECT_EQ (1, bb_b->succs->length ());
+  EXPECT_EQ (1, bb_c->preds->length ());
+  EXPECT_EQ (1, bb_c->succs->length ());
+  EXPECT_EQ (1, EXIT_BLOCK_PTR_FOR_FN (fun)->preds->length ());
+  EXPECT_EQ (NULL, EXIT_BLOCK_PTR_FOR_FN (fun)->succs);
+
+  /* Verify the dominance information
+     Each BB in our simple chain should be dominated by the one before
+     it.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  EXPECT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
+  EXPECT_EQ (bb_b, get_immediate_dominator (CDI_DOMINATORS, bb_c));
+  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
+  EXPECT_EQ (1, dom_by_b.length ());
+  EXPECT_EQ (bb_c, dom_by_b[0]);
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance: each BB in our chain is post-dominated
+     by the one after it.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  EXPECT_EQ (bb_b, get_immediate_dominator (CDI_POST_DOMINATORS, bb_a));
+  EXPECT_EQ (bb_c, get_immediate_dominator (CDI_POST_DOMINATORS, bb_b));
+  vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
+  EXPECT_EQ (1, postdom_by_b.length ());
+  EXPECT_EQ (bb_a, postdom_by_b[0]);
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+/* Verify a simple CFG of the form:
+     ENTRY
+       |
+       A
+      / \
+     /t  \f
+    B     C
+     \   /
+      \ /
+       D
+       |
+      EXIT.  */
+TEST_F (cfg_test, diamond)
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_test_diamond");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+
+  /* Create some empty blocks.  */
+  basic_block bb_a = create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun));
+  basic_block bb_b = create_empty_bb (bb_a);
+  basic_block bb_c = create_empty_bb (bb_a);
+  basic_block bb_d = create_empty_bb (bb_b);
+
+  EXPECT_EQ (6, n_basic_blocks_for_fn (fun));
+  EXPECT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create the edges.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), bb_a, EDGE_FALLTHRU);
+  make_edge (bb_a, bb_b, EDGE_TRUE_VALUE);
+  make_edge (bb_a, bb_c, EDGE_FALSE_VALUE);
+  make_edge (bb_b, bb_d, 0);
+  make_edge (bb_c, bb_d, 0);
+  make_edge (bb_d, EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+
+  /* Verify the edges.  */
+  EXPECT_EQ (6, n_edges_for_fn (fun));
+  EXPECT_EQ (1, bb_a->preds->length ());
+  EXPECT_EQ (2, bb_a->succs->length ());
+  EXPECT_EQ (1, bb_b->preds->length ());
+  EXPECT_EQ (1, bb_b->succs->length ());
+  EXPECT_EQ (1, bb_c->preds->length ());
+  EXPECT_EQ (1, bb_c->succs->length ());
+  EXPECT_EQ (2, bb_d->preds->length ());
+  EXPECT_EQ (1, bb_d->succs->length ());
+
+  /* Verify the dominance information.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  EXPECT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
+  EXPECT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_c));
+  EXPECT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_d));
+  vec<basic_block> dom_by_a = get_dominated_by (CDI_DOMINATORS, bb_a);
+  EXPECT_EQ (3, dom_by_a.length ()); /* B, C, D, in some order.  */
+  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
+  EXPECT_EQ (0, dom_by_b.length ());
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  EXPECT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_a));
+  EXPECT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_b));
+  EXPECT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_c));
+  vec<basic_block> postdom_by_d = get_dominated_by (CDI_POST_DOMINATORS, bb_d);
+  EXPECT_EQ (3, postdom_by_d.length ()); /* A, B, C in some order.  */
+  vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
+  EXPECT_EQ (0, postdom_by_b.length ());
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+/* Verify that we can handle a CFG containing a "complete" aka
+   fully-connected subgraph (where A B C D below all have edges
+   pointing to each other node, also to themselves).
+   e.g.:
+     ENTRY  EXIT
+       |    ^
+       |   /
+       |  /
+       | /
+       V/
+       A<--->B
+       ^^   ^^
+       | \ / |
+       |  X  |
+       | / \ |
+       VV   VV
+       C<--->D
+*/
+TEST_F (cfg_test, fully_connected)
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_fully_connected");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+
+  const int n = 4;
+
+  /* Create some empty blocks.  */
+  auto_vec <basic_block> subgraph_nodes;
+  for (int i = 0; i < n; i++)
+    subgraph_nodes.safe_push (create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun)));
+
+  EXPECT_EQ (n + 2, n_basic_blocks_for_fn (fun));
+  EXPECT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create the edges.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), subgraph_nodes[0], EDGE_FALLTHRU);
+  make_edge (subgraph_nodes[0], EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+  for (int i = 0; i < n; i++)
+    for (int j = 0; j < n; j++)
+      make_edge (subgraph_nodes[i], subgraph_nodes[j], 0);
+
+  /* Verify the edges.  */
+  EXPECT_EQ (2 + (n * n), n_edges_for_fn (fun));
+  /* The first one is linked to ENTRY/EXIT as well as itself and
+     everything else.  */
+  EXPECT_EQ (n + 1, subgraph_nodes[0]->preds->length ());
+  EXPECT_EQ (n + 1, subgraph_nodes[0]->succs->length ());
+  /* The other ones in the subgraph are linked to everything in
+     the subgraph (including themselves).  */
+  for (int i = 1; i < n; i++)
+    {
+      EXPECT_EQ (n, subgraph_nodes[i]->preds->length ());
+      EXPECT_EQ (n, subgraph_nodes[i]->succs->length ());
+    }
+
+  /* Verify the dominance information.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  /* The initial block in the subgraph should be dominated by ENTRY.  */
+  EXPECT_EQ (ENTRY_BLOCK_PTR_FOR_FN (fun),
+	     get_immediate_dominator (CDI_DOMINATORS,
+				      subgraph_nodes[0]));
+  /* Every other block in the subgraph should be dominated by the
+     initial block.  */
+  for (int i = 1; i < n; i++)
+    EXPECT_EQ (subgraph_nodes[0],
+	       get_immediate_dominator (CDI_DOMINATORS,
+					subgraph_nodes[i]));
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  /* The initial block in the subgraph should be postdominated by EXIT.  */
+  EXPECT_EQ (EXIT_BLOCK_PTR_FOR_FN (fun),
+	     get_immediate_dominator (CDI_POST_DOMINATORS,
+				      subgraph_nodes[0]));
+  /* Every other block in the subgraph should be postdominated by the
+     initial block, since that leads to EXIT.  */
+  for (int i = 1; i < n; i++)
+    EXPECT_EQ (subgraph_nodes[0],
+	       get_immediate_dominator (CDI_POST_DOMINATORS,
+					subgraph_nodes[i]));
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+}  /* anon namespace.  */
+
+/* TODO: test the dominator/postdominator logic with various graphs/nodes:
+   - loop
+   - nested loops
+   - switch statement (a block with many out-edges)
+   - something that jumps to itself
+   - etc  */
+
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 11/21] Add function-tests.c
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
                                             ` (13 preceding siblings ...)
  2016-06-01 21:10                           ` [PATCH 08/21] Add selftests to tree-cfg.c David Malcolm
@ 2016-06-01 21:10                           ` David Malcolm
  2016-06-01 21:11                           ` [PATCH 16/21] Add hash-map-tests.c David Malcolm
                                             ` (7 subsequent siblings)
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 21:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-functions.c):
  https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03310.html
with:

> There's some if (0) code in here that needs to be eliminated.

(done)

> The RTL case in particular is probably stretching the limits of what
> we can do with the framework right now. Or more correctly what folks
> are likely to write within this framework.
>
> We may need to build up a library of bits that do common things so
> that we're not repeating that stuff all over the place.
>
> As far as RTL testing, as you note, once we hit RTL we're going to
> have far more target dependencies to contend with. Testing will
> be nontrivial.
>
> OK if/when prereqs are approved. Minor twiddling if we end up moving
> it elsewhere or standardizing/reducing header files is pre-approved.

Like other moves, this one gains #if CHECKING_P, and the change of
include from gtest/gtest.h to selftest.h.

gcc/ChangeLog:
	* function-tests.c: New file.
---
 gcc/function-tests.c | 630 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 630 insertions(+)
 create mode 100644 gcc/function-tests.c

diff --git a/gcc/function-tests.c b/gcc/function-tests.c
new file mode 100644
index 0000000..58b27b8
--- /dev/null
+++ b/gcc/function-tests.c
@@ -0,0 +1,630 @@
+/* Unit tests for function-handling.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "hard-reg-set.h"
+#include "input.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "gimple-expr.h"
+#include "toplev.h"
+#include "print-tree.h"
+#include "tree-iterator.h"
+#include "gimplify.h"
+#include "tree-cfg.h"
+#include "basic-block.h"
+#include "double-int.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "stmt.h"
+#include "hash-table.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "context.h"
+#include "hash-map.h"
+#include "plugin-api.h"
+#include "ipa-ref.h"
+#include "cgraph.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+namespace {
+
+class function_test : public ::selftest::test
+{
+ protected:
+  tree
+  make_fndecl (tree return_type,
+	       const char *name,
+	       vec <tree> &param_types,
+	       bool is_variadic = false)
+  {
+    tree fn_type;
+    if (is_variadic)
+      fn_type = build_varargs_function_type_array (return_type,
+						   param_types.length (),
+						   param_types.address ());
+    else
+      fn_type = build_function_type_array (return_type,
+					   param_types.length (),
+					   param_types.address ());
+    /* FIXME: this uses input_location: */
+    tree fndecl = build_fn_decl (name, fn_type);
+
+    return fndecl;
+  }
+};
+
+TEST_F (function_test, fndecl_int_void)
+{
+  auto_vec <tree> param_types;
+  tree fndecl = make_fndecl (integer_type_node,
+			     "test_fndecl_int_void",
+			     param_types);
+  ASSERT_TRUE (fndecl != NULL);
+
+  /* Verify name of decl.  */
+  tree declname = DECL_NAME (fndecl);
+  ASSERT_TRUE (declname != NULL);
+  EXPECT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
+  /* We expect it to use a *copy* of the string we passed in.  */
+  const char *identifier_ptr = IDENTIFIER_POINTER (declname);
+  EXPECT_NE ("test_fndecl_int_void", identifier_ptr);
+  EXPECT_EQ (0, strcmp ("test_fndecl_int_void", identifier_ptr));
+
+  /* Verify type of fndecl.  */
+  EXPECT_EQ (FUNCTION_DECL, TREE_CODE (fndecl));
+  tree fntype = TREE_TYPE (fndecl);
+  EXPECT_EQ (FUNCTION_TYPE, TREE_CODE (fntype));
+
+  /* Verify return type.  */
+  EXPECT_EQ (integer_type_node, TREE_TYPE (fntype));
+
+  /* Verify "void" args.  */
+  tree argtypes = TYPE_ARG_TYPES (fntype);
+  EXPECT_EQ (TREE_LIST, TREE_CODE (argtypes));
+  EXPECT_EQ (void_type_node, TREE_VALUE (argtypes));
+  EXPECT_EQ (NULL, TREE_CHAIN (argtypes));
+}
+
+TEST_F (function_test, fndecl_float_intchar)
+{
+  auto_vec <tree> param_types;
+  param_types.safe_push (integer_type_node);
+  param_types.safe_push (char_type_node);
+  tree fndecl = make_fndecl (float_type_node,
+			     "test_fndecl_float_intchar",
+			     param_types);
+  ASSERT_TRUE (fndecl != NULL);
+
+  /* Verify name of decl.  */
+  tree declname = DECL_NAME (fndecl);
+  ASSERT_TRUE (declname != NULL);
+  EXPECT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
+  /* We expect it to use a *copy* of the string we passed in.  */
+  const char *identifier_ptr = IDENTIFIER_POINTER (declname);
+  EXPECT_NE ("test_fndecl_float_intchar", identifier_ptr);
+  EXPECT_EQ (0, strcmp ("test_fndecl_float_intchar", identifier_ptr));
+
+  /* Verify type of fndecl.  */
+  EXPECT_EQ (FUNCTION_DECL, TREE_CODE (fndecl));
+  tree fntype = TREE_TYPE (fndecl);
+  EXPECT_EQ (FUNCTION_TYPE, TREE_CODE (fntype));
+
+  /* Verify return type.  */
+  EXPECT_EQ (float_type_node, TREE_TYPE (fntype));
+
+  /* Verify "(int, char)" args.  */
+  tree arg0 = TYPE_ARG_TYPES (fntype);
+  EXPECT_EQ (TREE_LIST, TREE_CODE (arg0));
+  EXPECT_EQ (integer_type_node, TREE_VALUE (arg0));
+  tree arg1 = TREE_CHAIN (arg0);
+  ASSERT_TRUE (arg1 != NULL);
+  EXPECT_EQ (TREE_LIST, TREE_CODE (arg1));
+  EXPECT_EQ (char_type_node, TREE_VALUE (arg1));
+  tree argterm = TREE_CHAIN (arg1);
+  ASSERT_TRUE (argterm != NULL);
+  EXPECT_EQ (TREE_LIST, TREE_CODE (argterm));
+  EXPECT_EQ (void_type_node, TREE_VALUE (argterm));
+  EXPECT_EQ (NULL, TREE_CHAIN (argterm));
+}
+
+/* The test cases using this fixture take a trivial function:
+
+     int test_fn (void) { return 42; }
+
+   and test various conversions done to it:
+
+   - gimplification
+   - construction of the CFG
+   - conversion to SSA form
+   - expansion to RTL form
+
+   In avoid having one overlong test case, this is broken
+   up into separate test cases for each stage, with helper methods
+   in this fixture to minimize code duplication.
+
+   Another approach would be to attempt to directly construct a function
+   in the appropriate representation at each stage, though presumably
+   that would exhibit different kinds of failure compared to this
+   approach.  */
+
+class representation_test : public function_test
+{
+ protected:
+  /* Construct this function:
+       int test_fn (void) { return 42; }
+     in generic tree form.  Return the fndecl.  */
+  tree
+  build_trivial_generic_function ()
+  {
+    auto_vec <tree> param_types;
+    tree fndecl = make_fndecl (integer_type_node,
+			       "test_fn",
+			       param_types);
+    EXPECT_TRUE (fndecl != NULL);
+
+    /* Populate the function.  */
+    tree retval = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+			      NULL_TREE, integer_type_node);
+    DECL_ARTIFICIAL (retval) = 1;
+    DECL_IGNORED_P (retval) = 1;
+    DECL_RESULT (fndecl) = retval;
+
+    /* Create a BIND_EXPR, and within it, a statement list.  */
+    tree stmt_list = alloc_stmt_list ();
+    tree_stmt_iterator stmt_iter = tsi_start (stmt_list);
+    tree block = make_node (BLOCK);
+    tree bind_expr =
+      build3 (BIND_EXPR, void_type_node, NULL, stmt_list, block);
+
+    tree modify_retval = build2 (MODIFY_EXPR,
+				 integer_type_node,
+				 retval,
+				 build_int_cst (integer_type_node, 42));
+    tree return_stmt = build1 (RETURN_EXPR,
+			       integer_type_node,
+			       modify_retval);
+    tsi_link_after (&stmt_iter, return_stmt, TSI_CONTINUE_LINKING);
+
+    DECL_INITIAL (fndecl) = block;
+
+    /* how to add to function? the following appears to be how to
+       set the body of a fndecl: */
+    DECL_SAVED_TREE(fndecl) = bind_expr;
+
+    /* Ensure that locals appear in the debuginfo.  */
+    BLOCK_VARS (block) = BIND_EXPR_VARS (bind_expr);
+
+    return fndecl;
+  }
+
+  /* Construct this function:
+       int test_fn (void) { return 42; }
+     in "high gimple" form.  Return the fndecl.  */
+  tree
+  build_trivial_high_gimple_function ()
+  {
+    /* Construct a trivial function, and gimplify it: */
+    tree fndecl = build_trivial_generic_function ();
+    gimplify_function_tree (fndecl);
+    return fndecl;
+  }
+
+  /* Build a CFG for a function in gimple form.  */
+  void
+  build_cfg (tree fndecl)
+  {
+    function *fun = DECL_STRUCT_FUNCTION (fndecl);
+    ASSERT_TRUE (fun != NULL);
+    EXPECT_EQ (fndecl, fun->decl);
+
+    /* We first have to lower control flow; for our trivial test function
+       this gives us:
+	 test_fn ()
+	 {
+	   D.56 = 42;
+	   goto <D.57>;
+	   <D.57>:
+	   return D.56;
+	 }
+    */
+    gimple_opt_pass *lower_cf_pass = make_pass_lower_cf (g);
+    push_cfun (fun);
+    lower_cf_pass->execute (fun);
+    pop_cfun ();
+
+    /* We can now convert to CFG form; for our trivial test function this
+       gives us:
+	 test_fn ()
+	 {
+	   <bb 2>:
+	   D.56 = 42;
+	   return D.56;
+	 }
+    */
+    gimple_opt_pass *build_cfg_pass = make_pass_build_cfg (g);
+    push_cfun (fun);
+    build_cfg_pass->execute (fun);
+    pop_cfun ();
+  }
+
+  /* Convert a gimple+CFG function to SSA form.  */
+  void
+  convert_to_ssa (tree fndecl)
+  {
+    function *fun = DECL_STRUCT_FUNCTION (fndecl);
+    ASSERT_TRUE (fun != NULL);
+    EXPECT_EQ (fndecl, fun->decl);
+
+    gimple_opt_pass *pass_init_datastructures =
+      make_pass_init_datastructures (g);
+    gimple_opt_pass *build_ssa_pass = make_pass_build_ssa (g);
+    push_cfun (fun);
+    pass_init_datastructures->execute (fun);
+    build_ssa_pass->execute (fun);
+    pop_cfun ();
+  }
+
+  /* Assuming we have a simple 3-block CFG like this:
+       [ENTRY] -> [block2] -> [EXIT]
+     get the "real" basic block (block 2).  */
+  basic_block
+  get_real_block (function *fun)
+  {
+    EXPECT_TRUE (fun->cfg != NULL);
+    EXPECT_EQ (3, n_basic_blocks_for_fn (fun));
+    basic_block bb2 = (*fun->cfg->x_basic_block_info)[2];
+    EXPECT_TRUE (bb2 != NULL);
+    return bb2;
+  }
+
+  /* Verify that we have a simple 3-block CFG: the two "fake" ones, and
+     a "real" one:
+     [ENTRY] -> [block2] -> [EXIT].  */
+  void
+  verify_three_block_cfg (function *fun)
+  {
+    ASSERT_TRUE (fun->cfg != NULL);
+    EXPECT_EQ (3, n_basic_blocks_for_fn (fun));
+    EXPECT_EQ (2, n_edges_for_fn (fun));
+
+    /* The "fake" basic blocks.  */
+    basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (entry != NULL);
+    EXPECT_EQ (ENTRY_BLOCK, entry->index);
+
+    basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (exit != NULL);
+    EXPECT_EQ (EXIT_BLOCK, exit->index);
+
+    /* The "real" basic block.  */
+    basic_block bb2 = get_real_block (fun);
+    ASSERT_TRUE (bb2 != NULL);
+    EXPECT_EQ (2, bb2->index);
+
+    /* Verify connectivity.  */
+    EXPECT_EQ (NULL, entry->preds);
+    EXPECT_EQ (1, entry->succs->length ());
+
+    edge from_entry_to_bb2 = (*entry->succs)[0];
+    EXPECT_EQ (entry, from_entry_to_bb2->src);
+    EXPECT_EQ (bb2, from_entry_to_bb2->dest);
+
+    EXPECT_EQ (1, bb2->preds->length ());
+    EXPECT_EQ (from_entry_to_bb2, (*bb2->preds)[0]);
+    EXPECT_EQ (1, bb2->succs->length ());
+
+    edge from_bb2_to_exit = (*bb2->succs)[0];
+    EXPECT_EQ (bb2, from_bb2_to_exit->src);
+    EXPECT_EQ (exit, from_bb2_to_exit->dest);
+
+    EXPECT_EQ (1, exit->preds->length ());
+    EXPECT_EQ (from_bb2_to_exit, (*exit->preds)[0]);
+    EXPECT_EQ (NULL, exit->succs);
+  }
+
+  /* As above, but additionally verify the gimple statements are sane.  */
+  void
+  verify_three_block_gimple_cfg (function *fun)
+  {
+    verify_three_block_cfg (fun);
+
+    /* The "fake" basic blocks should be flagged as gimple, but with have no
+       statements.  */
+    basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (entry != NULL);
+    EXPECT_EQ (0, entry->flags & BB_RTL);
+    EXPECT_EQ (NULL, bb_seq (entry));
+
+    basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (exit != NULL);
+    EXPECT_EQ (0, entry->flags & BB_RTL);
+    EXPECT_EQ (NULL, bb_seq (exit));
+
+    /* The "real" basic block should be flagged as gimple, and have one
+       or more statements.  */
+    basic_block bb2 = get_real_block (fun);
+    ASSERT_TRUE (bb2 != NULL);
+    EXPECT_EQ (0, entry->flags & BB_RTL);
+    EXPECT_TRUE (bb_seq (bb2) != NULL);
+  }
+
+  /* As above, but additionally verify the RTL insns are sane.  */
+  void
+  verify_three_block_rtl_cfg (function *fun)
+  {
+    verify_three_block_cfg (fun);
+
+    /* The "fake" basic blocks should be flagged as RTL, but with no
+       insns.  */
+    basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (entry != NULL);
+    EXPECT_EQ (BB_RTL, entry->flags & BB_RTL);
+    EXPECT_EQ (NULL, BB_HEAD (entry));
+
+    basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+    ASSERT_TRUE (exit != NULL);
+    EXPECT_EQ (BB_RTL, entry->flags & BB_RTL);
+    EXPECT_EQ (NULL, BB_HEAD (exit));
+
+    /* The "real" basic block should be flagged as RTL, and have one
+       or more insns.  */
+    basic_block bb2 = get_real_block (fun);
+    ASSERT_TRUE (bb2 != NULL);
+    EXPECT_EQ (BB_RTL, entry->flags & BB_RTL);
+    EXPECT_TRUE (BB_HEAD (bb2) != NULL);
+  }
+
+};
+
+/* Test converting our trivial function:
+     int test_fn (void) { return 42; }
+   to gimple form.  */
+
+TEST_F (representation_test, gimplification)
+{
+  tree fndecl = build_trivial_generic_function ();
+
+  /* Convert to gimple: */
+  gimplify_function_tree (fndecl);
+
+  /* Verify that we got gimple out of it.  */
+
+  /* The function is now in GIMPLE form but the CFG has not been
+     built yet.  */
+
+  /* We should have a struct function for the decl.  */
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  EXPECT_EQ (fndecl, fun->decl);
+
+  /* We expect a GIMPLE_BIND, with two gimple statements within it:
+       tmp = 42;
+       return tmp;  */
+
+  gimple_seq seq_fn_body = gimple_body (fndecl);
+  EXPECT_TRUE (seq_fn_body != NULL);
+  gimple *bind_stmt = gimple_seq_first_stmt (seq_fn_body);
+  EXPECT_EQ (GIMPLE_BIND, gimple_code (bind_stmt));
+  EXPECT_EQ (NULL, bind_stmt->next);
+
+  gimple_seq seq_bind_body = gimple_bind_body (as_a <gbind *> (bind_stmt));
+
+  /* Verify that we have the 2 statements we expect.  */
+  EXPECT_TRUE (seq_bind_body != NULL);
+  gimple *stmt1 = gimple_seq_first_stmt (seq_bind_body);
+  ASSERT_TRUE (stmt1 != NULL);
+  EXPECT_EQ (GIMPLE_ASSIGN, gimple_code (stmt1));
+  gimple *stmt2 = stmt1->next;
+  ASSERT_TRUE (stmt2 != NULL);
+  EXPECT_EQ (stmt1, stmt2->prev);
+  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt2));
+}
+
+/* Test of building a CFG for a function in high gimple form.  */
+
+TEST_F (representation_test, building_cfg)
+{
+  /* Construct a trivial function, and gimplify it: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+
+  /* Build a CFG.  */
+  build_cfg (fndecl);
+
+  /* The CFG-building code constructs a 4-block cfg (with
+     ENTRY and EXIT):
+       test_fn ()
+       {
+         <bb 2>:
+	 D.65 = 42;
+
+	 <bb 3>:
+	 return D.65;
+       }
+     and then ought to merge blocks 2 and 3 in cleanup_tree_cfg.
+
+     Hence we should end up with a simple 3-block cfg, the two "fake" ones,
+     and a "real" one:
+       [ENTRY] -> [block2] -> [EXIT]
+     with code like this:
+	 test_fn ()
+	 {
+	   <bb 2>:
+	   D.56 = 42;
+	   return D.56;
+	 }
+  */
+  verify_three_block_gimple_cfg (fun);
+
+  /* Verify the statements within the "real" block.  */
+  basic_block bb2 = get_real_block (fun);
+  gimple *stmt_a = gimple_seq_first_stmt (bb_seq (bb2));
+  EXPECT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a));
+  gimple *stmt_b = stmt_a->next;
+  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt_b));
+  EXPECT_EQ (NULL, stmt_b->next);
+}
+
+/* Test of conversion of gimple to SSA form.  */
+TEST_F (representation_test, conversion_to_ssa)
+{
+  /* As above, construct a trivial function, gimplify it, and build a CFG: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  build_cfg (fndecl);
+
+  convert_to_ssa (fndecl);
+
+  verify_three_block_gimple_cfg (fun);
+
+  /* For out trivial test function we should now have something like
+     this:
+       test_fn ()
+       {
+	 <bb 2>:
+	 _1 = 42;
+	 return _1;
+       }
+  */
+  basic_block bb2 = get_real_block (fun);
+  gimple *stmt_a = gimple_seq_first_stmt (bb_seq (bb2));
+  EXPECT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a));
+
+  gimple *stmt_b = stmt_a->next;
+  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt_b));
+  EXPECT_EQ (NULL, stmt_b->next);
+
+  greturn *return_stmt = as_a <greturn *> (stmt_b);
+  EXPECT_EQ (SSA_NAME, TREE_CODE (gimple_return_retval (return_stmt)));
+}
+
+/* Test of expansion from gimple-ssa to RTL.  */
+
+TEST_F (representation_test, expansion_to_rtl)
+{
+  /* As above, construct a trivial function, gimplify it, build a CFG,
+     and convert to SSA: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  build_cfg (fndecl);
+  convert_to_ssa (fndecl);
+
+  /* We need a cgraph_node for it.  */
+  cgraph_node::get_create (fndecl);
+  /* Normally, cgraph_node::expand () would call
+     init_function_start (and a bunch of other stuff),
+     and invoke the expand pass, but it also runs
+     all of the other passes.  So just do the minimum
+     needed to get from gimple-SSA to RTL.  */
+  rtl_opt_pass *expand_pass = make_pass_expand (g);
+  push_cfun (fun);
+  init_function_start (fndecl);
+  expand_pass->execute (fun);
+  pop_cfun ();
+
+  /* On x86_64, I get this:
+       (note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+       (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
+       (insn 5 2 6 2 (set (reg:SI 87 [ D.59 ])
+			  (const_int 42 [0x2a])) -1 (nil))
+       (insn 6 5 10 2 (set (reg:SI 88 [ <retval> ])
+			   (reg:SI 87 [ D.59 ])) -1 (nil))
+       (insn 10 6 11 2 (set (reg/i:SI 0 ax)
+			    (reg:SI 88 [ <retval> ])) -1 (nil))
+       (insn 11 10 0 2 (use (reg/i:SI 0 ax)) -1 (nil))
+   */
+  verify_three_block_rtl_cfg (fun);
+
+  /* Verify as much of the RTL as we can whilst avoiding
+     target-specific behavior.  */
+  basic_block bb2 = get_real_block (fun);
+
+  /* Expect a NOTE_INSN_BASIC_BLOCK... */
+  rtx_insn *insn = BB_HEAD (bb2);
+  ASSERT_TRUE (insn != NULL);
+  EXPECT_EQ (NOTE, insn->code);
+  EXPECT_EQ (NOTE_INSN_BASIC_BLOCK, NOTE_KIND (insn));
+  EXPECT_EQ (bb2, NOTE_BASIC_BLOCK (insn));
+
+  /* ...followed by a NOTE_INSN_FUNCTION_BEG...  */
+  insn = NEXT_INSN (insn);
+  ASSERT_TRUE (insn != NULL);
+  EXPECT_EQ (NOTE, insn->code);
+  EXPECT_EQ (NOTE_INSN_FUNCTION_BEG, NOTE_KIND (insn));
+
+  /* ...followed by a SET of a reg to the const value.  */
+  insn = NEXT_INSN (insn);
+  ASSERT_TRUE (insn != NULL);
+  EXPECT_EQ (INSN, insn->code);
+  rtx pat = PATTERN (insn);
+  ASSERT_TRUE (pat != NULL);
+  EXPECT_EQ (SET, pat->code);
+  EXPECT_EQ (REG, SET_DEST (pat)->code);
+  EXPECT_EQ (CONST_INT, SET_SRC (pat)->code);
+  EXPECT_EQ (42, INTVAL (SET_SRC (pat)));
+
+  /* ...etc; any further checks are likely to over-specify things
+     and run us into target dependencies.  */
+}
+
+}  // anon namespace
+
+#endif /* #if CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 16/21] Add hash-map-tests.c
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
                                             ` (14 preceding siblings ...)
  2016-06-01 21:10                           ` [PATCH 11/21] Add function-tests.c David Malcolm
@ 2016-06-01 21:11                           ` David Malcolm
  2016-06-01 21:20                           ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) Sandra Loosemore
                                             ` (6 subsequent siblings)
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 21:11 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-hash-map.c):
 https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03301.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files is
> pre-approved.

This version moves the tests to gcc/hash-map-tests.c.

gcc/ChangeLog:
	* hash-map-tests.c: New file.
---
 gcc/hash-map-tests.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)
 create mode 100644 gcc/hash-map-tests.c

diff --git a/gcc/hash-map-tests.c b/gcc/hash-map-tests.c
new file mode 100644
index 0000000..8fc989a
--- /dev/null
+++ b/gcc/hash-map-tests.c
@@ -0,0 +1,81 @@
+/* Unit tests for hash-map.h.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+namespace {
+
+TEST (hash_map_test, map_of_strings_to_int)
+{
+  hash_map <const char *, int> m;
+
+  const char *ostrich = "ostrich";
+  const char *elephant = "elephant";
+  const char *ant = "ant";
+  const char *spider = "spider";
+  const char *millipede = "Illacme plenipes";
+  const char *eric = "half a bee";
+
+  /* A fresh hash_map should be empty.  */
+  EXPECT_EQ (0, m.elements ());
+  EXPECT_EQ (NULL, m.get (ostrich));
+
+  /* Populate the hash_map.  */
+  EXPECT_EQ (false, m.put (ostrich, 2));
+  EXPECT_EQ (false, m.put (elephant, 4));
+  EXPECT_EQ (false, m.put (ant, 6));
+  EXPECT_EQ (false, m.put (spider, 8));
+  EXPECT_EQ (false, m.put (millipede, 750));
+  EXPECT_EQ (false, m.put (eric, 3));
+
+  /* Verify that we can recover the stored values.  */
+  EXPECT_EQ (6, m.elements ());
+  EXPECT_EQ (2, *m.get (ostrich));
+  EXPECT_EQ (4, *m.get (elephant));
+  EXPECT_EQ (6, *m.get (ant));
+  EXPECT_EQ (8, *m.get (spider));
+  EXPECT_EQ (750, *m.get (millipede));
+  EXPECT_EQ (3, *m.get (eric));
+
+  /* Verify removing an item.  */
+  m.remove (eric);
+  EXPECT_EQ (5, m.elements ());
+  EXPECT_EQ (NULL, m.get (eric));
+}
+
+}  /* anon namespace.  */
+
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5)
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
                                             ` (15 preceding siblings ...)
  2016-06-01 21:11                           ` [PATCH 16/21] Add hash-map-tests.c David Malcolm
@ 2016-06-01 21:20                           ` Sandra Loosemore
  2016-06-02 13:08                             ` David Malcolm
  2016-06-01 21:21                           ` [PATCH 05/21] Add selftests for diagnostic-show-locus.c David Malcolm
                                             ` (5 subsequent siblings)
  22 siblings, 1 reply; 176+ messages in thread
From: Sandra Loosemore @ 2016-06-01 21:20 UTC (permalink / raw)
  To: David Malcolm, gcc-patches; +Cc: Bernd Schmidt, Jeff Law

On 06/01/2016 03:19 PM, David Malcolm wrote:
> This is effectively v5 of the unittests proposal; for the earlier
> versions see:
>   * v1: https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00765.html
>   * v2: https://gcc.gnu.org/ml/gcc-patches/2015-06/msg01224.html
>   * v3: https://gcc.gnu.org/ml/gcc-patches/2015-10/msg02947.html
>   * v4: https://gcc.gnu.org/ml/gcc-patches/2015-11/msg02379.html
>
> Bernd said (in https://gcc.gnu.org/ml/gcc-patches/2015-11/msg01981.html ):
>> For some of the simpler infrastructure tests such as the ones in this
>> patch kit (bitmap, vec or wide-int functionality testing and such),
>> we had the idea of putting these into every ENABLE_CHECKING compiler,
>> and run them after building stage1, controlled by a -fself-test flag.
>> It's better to detect such basic failures early rather than complete
>> a full bootstrap and test cycle. It also keeps the tests alongside the
>> rest of the implementation, which I consider desirable for such
>> relatively simple data structures."
>
> So the main difference is this version of the patch kit is that the tests
> are run much earlier: rather than have a DejaGnu test below gcc.dg that
> compiles a dummy file with -fself-test, in this iteration, gcc/Makefile.in
> is updated so that the selftests are run during the build.
>
> [snip]

I don't see any documentation here for the new command-line options.  If 
these are not intended to be user-visible, I think you should set the 
"Undocumented" flag for them in the .opt file instead.

-Sandra

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 05/21] Add selftests for diagnostic-show-locus.c
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
                                             ` (16 preceding siblings ...)
  2016-06-01 21:20                           ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) Sandra Loosemore
@ 2016-06-01 21:21                           ` David Malcolm
  2016-06-01 21:22                           ` [PATCH 19/21] Add rtl-tests.c David Malcolm
                                             ` (4 subsequent siblings)
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 21:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Here's another example of unit tests, this time for
an implementation detail within diagnostic-show-locus.c.

gcc/ChangeLog:
	* diagnostic-show-locus.c: Include "selftest.h".
	(class range_contains_point_tests): New class.
	(TEST_F (range_contains_point_tests, single_point)): New test.
	(TEST_F (range_contains_point_tests, single_line)): New test.
	(TEST_F (range_contains_point_tests, multiple_lines)): New test.
---
 gcc/diagnostic-show-locus.c | 113 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 113 insertions(+)

diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
index eeccee5..283a260 100644
--- a/gcc/diagnostic-show-locus.c
+++ b/gcc/diagnostic-show-locus.c
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "backtrace.h"
 #include "diagnostic.h"
 #include "diagnostic-color.h"
+#include "selftest.h"
 
 #ifdef HAVE_TERMIOS_H
 # include <termios.h>
@@ -442,6 +443,118 @@ layout_range::contains_point (int row, int column) const
   return column <= m_finish.m_column;
 }
 
+#if CHECKING_P
+
+/* A fixture for testing layout_range::contains_point.  */
+
+class range_contains_point_tests : public ::selftest::test
+{
+ protected:
+  layout_range
+  make_range (int start_line, int start_col,
+	      int end_line, int end_col)
+  {
+    const expanded_location start_exploc
+      = {"test.c", start_line, start_col, NULL, false};
+    expanded_location finish_exploc
+      = {"test.c", end_line, end_col, NULL, false};
+
+    return layout_range (&start_exploc, &finish_exploc, false,
+			 &start_exploc);
+  }
+};
+
+TEST_F (range_contains_point_tests, single_point)
+{
+  /* A range with start==end.  */
+  layout_range point = make_range (7, 10, 7, 10);
+
+  /* Before the line. */
+  EXPECT_FALSE (point.contains_point (6, 1));
+
+  /* On the line, but before start.  */
+  EXPECT_FALSE (point.contains_point (7, 9));
+
+  /* At the point.  */
+  EXPECT_TRUE (point.contains_point (7, 10));
+
+  /* On the line, after the point.  */
+  EXPECT_FALSE (point.contains_point (7, 11));
+
+  /* After the line.  */
+  EXPECT_FALSE (point.contains_point (8, 1));
+}
+
+TEST_F (range_contains_point_tests, single_line)
+{
+  /* The single-line example from above.  */
+  layout_range example_a = make_range (2, 22, 2, 38);
+
+  /* Before the line. */
+  EXPECT_FALSE (example_a.contains_point (1, 1));
+
+  /* On the line, but before start.  */
+  EXPECT_FALSE (example_a.contains_point (2, 21));
+
+  /* On the line, at the start.  */
+  EXPECT_TRUE (example_a.contains_point (2, 22));
+
+  /* On the line, within the range.  */
+  EXPECT_TRUE (example_a.contains_point (2, 23));
+
+  /* On the line, at the end.  */
+  EXPECT_TRUE (example_a.contains_point (2, 38));
+
+  /* On the line, after the end.  */
+  EXPECT_FALSE (example_a.contains_point (2, 39));
+
+  /* After the line.  */
+  EXPECT_FALSE (example_a.contains_point (2, 39));
+}
+
+TEST_F (range_contains_point_tests, multiple_lines)
+{
+  /* The multi-line example from above.  */
+  layout_range example_b = make_range (3, 14, 5, 8);
+
+  /* Before first line. */
+  EXPECT_FALSE (example_b.contains_point (1, 1));
+
+  /* On the first line, but before start.  */
+  EXPECT_FALSE (example_b.contains_point (3, 13));
+
+  /* At the start.  */
+  EXPECT_TRUE (example_b.contains_point (3, 14));
+
+  /* On the first line, within the range.  */
+  EXPECT_TRUE (example_b.contains_point (3, 15));
+
+  /* On an interior line.
+     The column number should not matter; try various boundary
+     values.  */
+  EXPECT_TRUE (example_b.contains_point (4, 1));
+  EXPECT_TRUE (example_b.contains_point (4, 7));
+  EXPECT_TRUE (example_b.contains_point (4, 8));
+  EXPECT_TRUE (example_b.contains_point (4, 9));
+  EXPECT_TRUE (example_b.contains_point (4, 13));
+  EXPECT_TRUE (example_b.contains_point (4, 14));
+  EXPECT_TRUE (example_b.contains_point (4, 15));
+
+  /* On the final line, before the end.  */
+  EXPECT_TRUE (example_b.contains_point (5, 7));
+
+  /* On the final line, at the end.  */
+  EXPECT_TRUE (example_b.contains_point (5, 8));
+
+  /* On the final line, after the end.  */
+  EXPECT_FALSE (example_b.contains_point (5, 9));
+
+  /* After the line.  */
+  EXPECT_FALSE (example_b.contains_point (6, 1));
+}
+
+#endif /* #if CHECKING_P */
+
 /* Given a source line LINE of length LINE_WIDTH, determine the width
    without any trailing whitespace.  */
 
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 19/21] Add rtl-tests.c
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
                                             ` (17 preceding siblings ...)
  2016-06-01 21:21                           ` [PATCH 05/21] Add selftests for diagnostic-show-locus.c David Malcolm
@ 2016-06-01 21:22                           ` David Malcolm
  2016-06-01 21:23                           ` [PATCH 15/21] Add selftests to gimple.c David Malcolm
                                             ` (3 subsequent siblings)
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 21:22 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-rtl.c):
 https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03302.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files is
>pre-approved.

This version puts the tests in gcc/rtl-tests.c.

gcc/ChangeLog:
	* rtl-tests.c: New file.
---
 gcc/rtl-tests.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 98 insertions(+)
 create mode 100644 gcc/rtl-tests.c

diff --git a/gcc/rtl-tests.c b/gcc/rtl-tests.c
new file mode 100644
index 0000000..611d82a
--- /dev/null
+++ b/gcc/rtl-tests.c
@@ -0,0 +1,98 @@
+/* Unit tests for RTL-handling.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "pretty-print.h"
+#include "cfgbuild.h"
+#include "print-rtl.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+namespace {
+
+class rtl_test : public ::selftest::test
+{
+ protected:
+  void
+  verify_print_pattern (const char *expected, rtx pat)
+  {
+    pretty_printer pp;
+    print_pattern (&pp, pat, 1);
+    EXPECT_STREQ (expected, pp_formatted_text (&pp));
+  }
+};
+
+/* Unit testing of "single_set".  */
+TEST_F (rtl_test, test_single_set)
+{
+  /* A label is not a SET.  */
+  EXPECT_EQ (NULL_RTX, single_set (gen_label_rtx ()));
+
+  /* An unconditional jump insn is a single SET.  */
+  rtx set_pc = gen_rtx_SET (pc_rtx,
+			    gen_rtx_LABEL_REF (VOIDmode,
+					       gen_label_rtx ()));
+  rtx_insn *jump_insn = emit_jump_insn (set_pc);
+  EXPECT_EQ (set_pc, single_set (jump_insn));
+
+  /* etc */
+}
+
+TEST_F (rtl_test, uncond_jump)
+{
+  rtx_insn *label = gen_label_rtx ();
+  rtx jump_pat = gen_rtx_SET (pc_rtx,
+			      gen_rtx_LABEL_REF (VOIDmode,
+						 label));
+  EXPECT_EQ (SET, jump_pat->code);
+  EXPECT_EQ (LABEL_REF, SET_SRC (jump_pat)->code);
+  EXPECT_EQ (label, LABEL_REF_LABEL (SET_SRC (jump_pat)));
+  EXPECT_EQ (PC, SET_DEST (jump_pat)->code);
+
+  verify_print_pattern ("pc=L0", jump_pat);
+
+  rtx_insn *jump_insn = emit_jump_insn (jump_pat);
+  EXPECT_FALSE (any_condjump_p (jump_insn));
+  EXPECT_TRUE (any_uncondjump_p (jump_insn));
+  EXPECT_TRUE (pc_set (jump_insn));
+  EXPECT_TRUE (simplejump_p (jump_insn));
+  EXPECT_TRUE (onlyjump_p (jump_insn));
+  EXPECT_TRUE (control_flow_insn_p (jump_insn));
+}
+
+}  /* anon namespace.  */
+
+#endif /* #if CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 15/21] Add selftests to gimple.c
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
                                             ` (18 preceding siblings ...)
  2016-06-01 21:22                           ` [PATCH 19/21] Add rtl-tests.c David Malcolm
@ 2016-06-01 21:23                           ` David Malcolm
  2016-06-01 21:26                           ` [PATCH 14/21] Remove x86_64-isms in function-tests.c David Malcolm
                                             ` (2 subsequent siblings)
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 21:23 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-gimple.c):
 https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03304.html

> Comment indicates addition. But code actually generates a
> MULT_EXPR. Please fix.
Fixed

> OK if/when prereqs are approved. Minor twiddling if we end
> up moving it elsewhere or standardizing/reducing header files
> is pre-approved.

This version moves the tests into gimple.c.

gcc/ChangeLog:
	* gimple.c: Include "selftest.h".
	Include "gimple-pretty-print.h".
	(class gimple_test): New subclass.
	(gimple_test, assign_single): New selftest.
	(gimple_test, assign_binop): New selftest.
	(gimple_test, nop_stmt): New selftest.
	(gimple_test, return_stmt): New selftest.
	(gimple_test, return_without_value): New selftest.
---
 gcc/gimple.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 103 insertions(+)

diff --git a/gcc/gimple.c b/gcc/gimple.c
index d822fab..b5d7391 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-walk.h"
 #include "gimplify.h"
 #include "target.h"
+#include "selftest.h"
+#include "gimple-pretty-print.h"
 
 
 /* All the tuples have their operand vector (if present) at the very bottom
@@ -3016,3 +3018,104 @@ maybe_remove_unused_call_args (struct function *fn, gimple *stmt)
       update_stmt_fn (fn, stmt);
     }
 }
+
+#if CHECKING_P
+
+namespace {
+
+class gimple_test : public ::selftest::test
+{
+ protected:
+  void
+  verify_gimple_pp (const char *expected, gimple *stmt)
+  {
+    pretty_printer pp;
+    pp_gimple_stmt_1 (&pp, stmt, 0 /* spc */, 0 /* flags */);
+    EXPECT_STREQ (expected, pp_formatted_text (&pp));
+  }
+};
+
+TEST_F (gimple_test, assign_single)
+{
+  /* Build "tmp = 5;"  */
+  tree type = integer_type_node;
+  tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			 get_identifier ("tmp"),
+			 type);
+  tree rhs = build_int_cst (type, 5);
+  gassign *stmt = gimple_build_assign (lhs, rhs);
+  verify_gimple_pp ("tmp = 5;", stmt);
+
+  EXPECT_TRUE (is_gimple_assign (stmt));
+  EXPECT_EQ (lhs, gimple_assign_lhs (stmt));
+  EXPECT_EQ (lhs, gimple_get_lhs (stmt));
+  EXPECT_EQ (rhs, gimple_assign_rhs1 (stmt));
+  EXPECT_EQ (NULL, gimple_assign_rhs2 (stmt));
+  EXPECT_EQ (NULL, gimple_assign_rhs3 (stmt));
+  EXPECT_TRUE (gimple_assign_single_p (stmt));
+  EXPECT_EQ (INTEGER_CST, gimple_assign_rhs_code (stmt));
+}
+
+TEST_F (gimple_test, assign_binop)
+{
+  /* Build "tmp = a * b;"  */
+  tree type = integer_type_node;
+  tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			 get_identifier ("tmp"),
+			 type);
+  tree a = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		       get_identifier ("a"),
+		       type);
+  tree b = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		       get_identifier ("b"),
+		       type);
+  gassign *stmt = gimple_build_assign (lhs, MULT_EXPR, a, b);
+  verify_gimple_pp ("tmp = a * b;", stmt);
+
+  EXPECT_TRUE (is_gimple_assign (stmt));
+  EXPECT_EQ (lhs, gimple_assign_lhs (stmt));
+  EXPECT_EQ (lhs, gimple_get_lhs (stmt));
+  EXPECT_EQ (a, gimple_assign_rhs1 (stmt));
+  EXPECT_EQ (b, gimple_assign_rhs2 (stmt));
+  EXPECT_EQ (NULL, gimple_assign_rhs3 (stmt));
+  EXPECT_FALSE (gimple_assign_single_p (stmt));
+  EXPECT_EQ (MULT_EXPR, gimple_assign_rhs_code (stmt));
+}
+
+TEST_F (gimple_test, nop_stmt)
+{
+  gimple *stmt = gimple_build_nop ();
+  verify_gimple_pp ("GIMPLE_NOP", stmt);
+  EXPECT_EQ (GIMPLE_NOP, gimple_code (stmt));
+  EXPECT_EQ (NULL, gimple_get_lhs (stmt));
+  EXPECT_FALSE (gimple_assign_single_p (stmt));
+}
+
+TEST_F (gimple_test, return_stmt)
+{
+  /* Build "return 7;"  */
+  tree type = integer_type_node;
+  tree val = build_int_cst (type, 7);
+  greturn *stmt = gimple_build_return (val);
+  verify_gimple_pp ("return 7;", stmt);
+
+  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt));
+  EXPECT_EQ (NULL, gimple_get_lhs (stmt));
+  EXPECT_EQ (val, gimple_return_retval (stmt));
+  EXPECT_FALSE (gimple_assign_single_p (stmt));
+}
+
+TEST_F (gimple_test, return_without_value)
+{
+  greturn *stmt = gimple_build_return (NULL);
+  verify_gimple_pp ("return;", stmt);
+
+  EXPECT_EQ (GIMPLE_RETURN, gimple_code (stmt));
+  EXPECT_EQ (NULL, gimple_get_lhs (stmt));
+  EXPECT_EQ (NULL, gimple_return_retval (stmt));
+  EXPECT_FALSE (gimple_assign_single_p (stmt));
+}
+
+}  /* anon namespace.  */
+
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 14/21] Remove x86_64-isms in function-tests.c
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
                                             ` (19 preceding siblings ...)
  2016-06-01 21:23                           ` [PATCH 15/21] Add selftests to gimple.c David Malcolm
@ 2016-06-01 21:26                           ` David Malcolm
  2016-06-01 21:29                           ` [PATCH 13/21] Fixup to function-tests.c David Malcolm
  2016-06-02 10:30                           ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) Bernd Schmidt
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 21:26 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

gcc/ChangeLog:
	* function-tests.c (TEST_F (representation_test, expansion_to_rtl)):
	Remove x86_64-isms.
---
 gcc/function-tests.c | 36 ++++++++++++++++++------------------
 1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/gcc/function-tests.c b/gcc/function-tests.c
index e5b5c63..56b04cd 100644
--- a/gcc/function-tests.c
+++ b/gcc/function-tests.c
@@ -589,7 +589,24 @@ TEST_F (representation_test, expansion_to_rtl)
        (insn 10 6 11 2 (set (reg/i:SI 0 ax)
 			    (reg:SI 88 [ <retval> ])) -1 (nil))
        (insn 11 10 0 2 (use (reg/i:SI 0 ax)) -1 (nil))
-   */
+
+     On cr16-elf I get this:
+       (note 4 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+       (insn 2 4 3 2 (set (reg:SI 24)
+	    (reg/f:SI 16 virtual-incoming-args)) -1
+	  (nil))
+       (note 3 2 6 2 NOTE_INSN_FUNCTION_BEG)
+       (insn 6 3 7 2 (set (reg:HI 22 [ _1 ])
+	    (const_int 42 [0x2a])) -1
+	 (nil))
+       (insn 7 6 11 2 (set (reg:HI 23 [ <retval> ])
+	   (reg:HI 22 [ _1 ])) -1
+	 (nil))
+       (insn 11 7 12 2 (set (reg/i:HI 0 r0)
+	   (reg:HI 23 [ <retval> ])) -1
+	 (nil))
+       (insn 12 11 0 2 (use (reg/i:HI 0 r0)) -1
+	 (nil)).  */
   verify_three_block_rtl_cfg (fun);
 
   /* Verify as much of the RTL as we can whilst avoiding
@@ -603,23 +620,6 @@ TEST_F (representation_test, expansion_to_rtl)
   EXPECT_EQ (NOTE_INSN_BASIC_BLOCK, NOTE_KIND (insn));
   EXPECT_EQ (bb2, NOTE_BASIC_BLOCK (insn));
 
-  /* ...followed by a NOTE_INSN_FUNCTION_BEG...  */
-  insn = NEXT_INSN (insn);
-  ASSERT_TRUE (insn != NULL);
-  EXPECT_EQ (NOTE, insn->code);
-  EXPECT_EQ (NOTE_INSN_FUNCTION_BEG, NOTE_KIND (insn));
-
-  /* ...followed by a SET of a reg to the const value.  */
-  insn = NEXT_INSN (insn);
-  ASSERT_TRUE (insn != NULL);
-  EXPECT_EQ (INSN, insn->code);
-  rtx pat = PATTERN (insn);
-  ASSERT_TRUE (pat != NULL);
-  EXPECT_EQ (SET, pat->code);
-  EXPECT_EQ (REG, SET_DEST (pat)->code);
-  EXPECT_EQ (CONST_INT, SET_SRC (pat)->code);
-  EXPECT_EQ (42, INTVAL (SET_SRC (pat)));
-
   /* ...etc; any further checks are likely to over-specify things
      and run us into target dependencies.  */
 }
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 13/21] Fixup to function-tests.c
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
                                             ` (20 preceding siblings ...)
  2016-06-01 21:26                           ` [PATCH 14/21] Remove x86_64-isms in function-tests.c David Malcolm
@ 2016-06-01 21:29                           ` David Malcolm
  2016-06-02 10:30                           ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) Bernd Schmidt
  22 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-01 21:29 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

r235817 removed pass_init_datastructures, so function-tests.c no
longer needs it.

gcc/ChangeLog:
	* function-tests.c (representation_test::convert_to_ssa): Drop
	pass_init_datastructures.
---
 gcc/function-tests.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/gcc/function-tests.c b/gcc/function-tests.c
index db105bf..e5b5c63 100644
--- a/gcc/function-tests.c
+++ b/gcc/function-tests.c
@@ -312,11 +312,8 @@ class representation_test : public function_test
     ASSERT_TRUE (fun != NULL);
     EXPECT_EQ (fndecl, fun->decl);
 
-    gimple_opt_pass *pass_init_datastructures =
-      make_pass_init_datastructures (g);
     gimple_opt_pass *build_ssa_pass = make_pass_build_ssa (g);
     push_cfun (fun);
-    pass_init_datastructures->execute (fun);
     build_ssa_pass->execute (fun);
     pop_cfun ();
   }
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5)
  2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
                                             ` (21 preceding siblings ...)
  2016-06-01 21:29                           ` [PATCH 13/21] Fixup to function-tests.c David Malcolm
@ 2016-06-02 10:30                           ` Bernd Schmidt
  2016-06-02 13:41                             ` David Malcolm
  22 siblings, 1 reply; 176+ messages in thread
From: Bernd Schmidt @ 2016-06-02 10:30 UTC (permalink / raw)
  To: David Malcolm, gcc-patches; +Cc: Jeff Law

On 06/01/2016 11:19 PM, David Malcolm wrote:
> This is effectively v5 of the unittests proposal; for the earlier
> versions see:

In general: nice to see this moving forward.

There are some issues with the patch kit, some patches seem to fix 
issues with earlier ones (#3 or #13). One patch adds a sorry, the next 
changes it to inform; patch #1 adds includes top toplev.c without adding 
the included files. All these issues should be resolved: any patch 
series should compile if it is applied only partially up to a point; no 
early patch should depend on later ones. Also, bugfixes and behaviour 
changes should be merged directly into the code so as to not hopelessly 
confuse the reviewers.

Some of the cover letters, in particular #1 seem to contain outdated 
information.

> I also patched things so that it aborts on the first failure, making
> failures easy to track down in the debugger, though requiring us to
> make the selftests robust.

Is there any kind of doubt that this is a good requirement?

> * conversion of the Levenshtein selftest from a plugin to using
>    -fself-test (we could move various other tests from plugins to run
>    earlier).

That sounds good.

> Patch 4 shows a way of filtering the tests using a command-line regex.

What's the use case for this?

> For (a), this version of the patch kit switches to stopping at the
> first failure.
> For (b), this version of the patch kit stays with auto-registration.
> For (c), this version stays with a "lite" version of GTest.
>
> Thoughts?   Does the "running tests early" approach suggest answers to
> these?

I think this is mostly a good resolution, although I have one particular 
issue that rubs me the wrong way where I'd go even "liter" on the GTest. 
In my view, tests are functions, and using object-orientation leads to 
oddly contorted code. An example can be found in patch #5:

+class range_contains_point_tests : public ::selftest::test
+{
+ protected:
+  layout_range
+  make_range (int start_line, int start_col,
+	      int end_line, int end_col)
(note also that this defeats the purpose of the GNU function formatting 
which is to enable grep ^function_name to find them)
+  {
+    const expanded_location start_exploc
+      = {"test.c", start_line, start_col, NULL, false};
+    expanded_location finish_exploc
+      = {"test.c", end_line, end_col, NULL, false};
+
+    return layout_range (&start_exploc, &finish_exploc, false,
+			 &start_exploc);
+  }
+};

I think I raised this before, but defining a class only to define 
functions inside them seems relatively pointless; if anything you want 
namespaces. This one doesn't even seem to contain any references to the 
selftest framework so it could immediately be converted to a function.

Other such cases appear to use the EXPECT_EQ etc. macros, which call 
pass and fail methods, but these just delegate immediately to the 
runner's pass and fail. Which then raises the question whether runner 
needs to be an object if there's only ever going to be one - once again 
I think a functional rather than object-oriented style would be more 
suitable to the problem. The main (only?) reason to have tests declared 
as objects is for the auto-registration, beyond that it serves very 
little purpose.


There are some inconsistent spellings of an end comment across the series:
+}  // anon namespace
+}  /* anon namespace.  */

I wasn't sure we were doing these at all, but it turns out the former is 
the canonical one (with a single space).


Bernd

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5)
  2016-06-01 21:20                           ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) Sandra Loosemore
@ 2016-06-02 13:08                             ` David Malcolm
  0 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-02 13:08 UTC (permalink / raw)
  To: Sandra Loosemore, gcc-patches; +Cc: Bernd Schmidt, Jeff Law

On Wed, 2016-06-01 at 15:20 -0600, Sandra Loosemore wrote:
> On 06/01/2016 03:19 PM, David Malcolm wrote:
> > This is effectively v5 of the unittests proposal; for the earlier
> > versions see:
> >   * v1: https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00765.html
> >   * v2: https://gcc.gnu.org/ml/gcc-patches/2015-06/msg01224.html
> >   * v3: https://gcc.gnu.org/ml/gcc-patches/2015-10/msg02947.html
> >   * v4: https://gcc.gnu.org/ml/gcc-patches/2015-11/msg02379.html
> > 
> > Bernd said (in 
> > https://gcc.gnu.org/ml/gcc-patches/2015-11/msg01981.html ):
> > > For some of the simpler infrastructure tests such as the ones in
> > > this
> > > patch kit (bitmap, vec or wide-int functionality testing and
> > > such),
> > > we had the idea of putting these into every ENABLE_CHECKING
> > > compiler,
> > > and run them after building stage1, controlled by a -fself-test
> > > flag.
> > > It's better to detect such basic failures early rather than
> > > complete
> > > a full bootstrap and test cycle. It also keeps the tests
> > > alongside the
> > > rest of the implementation, which I consider desirable for such
> > > relatively simple data structures."
> > 
> > So the main difference is this version of the patch kit is that the
> > tests
> > are run much earlier: rather than have a DejaGnu test below gcc.dg
> > that
> > compiles a dummy file with -fself-test, in this iteration,
> > gcc/Makefile.in
> > is updated so that the selftests are run during the build.
> > 
> > [snip]
> 
> I don't see any documentation here for the new command-line options. 
>  If 
> these are not intended to be user-visible, I think you should set the
> "Undocumented" flag for them in the .opt file instead.

Thanks; I'll do that in the next iteration of the patches.

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5)
  2016-06-02 10:30                           ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) Bernd Schmidt
@ 2016-06-02 13:41                             ` David Malcolm
  2016-06-02 20:41                               ` [PATCH 00/16] v6 of -fself-test/unit-testing patch David Malcolm
  0 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2016-06-02 13:41 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches; +Cc: Jeff Law

On Thu, 2016-06-02 at 12:29 +0200, Bernd Schmidt wrote:
> On 06/01/2016 11:19 PM, David Malcolm wrote:
> > This is effectively v5 of the unittests proposal; for the earlier
> > versions see:
> 
> In general: nice to see this moving forward.

Thanks.

> There are some issues with the patch kit, some patches seem to fix 
> issues with earlier ones (#3 or #13). One patch adds a sorry, the
> next 
> changes it to inform; patch #1 adds includes top toplev.c without
> adding 
> the included files. All these issues should be resolved: any patch 
> series should compile if it is applied only partially up to a point;
> no 
> early patch should depend on later ones. Also, bugfixes and behaviour
> changes should be merged directly into the code so as to not
> hopelessly 
> confuse the reviewers.
> Some of the cover letters, in particular #1 seem to contain outdated 
> information.

Sorry about that.  I was hoping to emphasize the changes from the last
version, but clearly it made things more confusing.

> > I also patched things so that it aborts on the first failure,
> > making
> > failures easy to track down in the debugger, though requiring us to
> > make the selftests robust.
> 
> Is there any kind of doubt that this is a good requirement?

I was uncertain about how acceptable the "run the tests from within
gcc/Makefile.in" approach is, so I was hedging my bets somewhat in the
kit.  It seems like you do like the gcc/Makefile.in approach, so this
implies each of:
(1) that tests should be fast (which is why I left out the test-ggc
tests in this iteration for now, as one of them is relatively slow)
(2) that tests must be 100% reliable
(3) it must be trivially easy to track down failures (since in this
approach test failure means build failure); "make selftests-gdb" is the
solution here

Given (3), this implies that we should halt on the first failure (as in
this version of the kit).  My experience when writing new tests and
experimenting with the gcc/Makefile.in approach was that "halt on first
failure" was much easier to work with than "run everything and report".


> > * conversion of the Levenshtein selftest from a plugin to using
> >    -fself-test (we could move various other tests from plugins to
> > run
> >    earlier).
> 
> That sounds good.
> 
> > Patch 4 shows a way of filtering the tests using a command-line
> > regex.
> 
> What's the use case for this?

Say there's a problem with many tests and that you suspect an issue in,
say, bitmap.c.  This would let you run e.g. ".*bitmap.*" to better
isolate the issue.

Maybe this suggests that we should go even simpler, and hard-code the
order in which tests run, manually encoding the dependencies (e.g. test
the fundamental types first, then test the things that build on top of
them, etc).  This would be losing auto-registration, but has the virtue
of simplicity.

Thought experiment: imagine trying to bring up gcc on a new host, and
3/4 of the self tests are failing; it turns out to be some sizeof()
assumption about int vs long or somesuch in one of the fundamental data
structures.  How do we make it easy to isolate such a problem?

> > For (a), this version of the patch kit switches to stopping at the
> > first failure.
> > For (b), this version of the patch kit stays with auto
> > -registration.
> > For (c), this version stays with a "lite" version of GTest.
> > 
> > Thoughts?   Does the "running tests early" approach suggest answers
> > to
> > these?
> 
> I think this is mostly a good resolution, 

Given that we're going with "halt on first failure", that means that
there's no longer a distinction between EXPECT_EQ and ASSERT_EQ.  I'll
eliminate the former in favor of the latter.

> although I have one particular 
> issue that rubs me the wrong way where I'd go even "liter" on the
> GTest. 
> In my view, tests are functions, and using object-orientation leads
> to 
> oddly contorted code. An example can be found in patch #5:
> 
> +class range_contains_point_tests : public ::selftest::test
> +{
> + protected:
> +  layout_range
> +  make_range (int start_line, int start_col,
> +	      int end_line, int end_col)
> (note also that this defeats the purpose of the GNU function
> formatting 
> which is to enable grep ^function_name to find them)
> +  {
> +    const expanded_location start_exploc
> +      = {"test.c", start_line, start_col, NULL, false};
> +    expanded_location finish_exploc
> +      = {"test.c", end_line, end_col, NULL, false};
> +
> +    return layout_range (&start_exploc, &finish_exploc, false,
> +			 &start_exploc);
> +  }
> +};
> 
> I think I raised this before, but defining a class only to define 
> functions inside them seems relatively pointless; if anything you
> want 
> namespaces. This one doesn't even seem to contain any references to
> the 
> selftest framework so it could immediately be converted to a
> function.
> 
> Other such cases appear to use the EXPECT_EQ etc. macros, which call 
> pass and fail methods, but these just delegate immediately to the 
> runner's pass and fail. Which then raises the question whether runner
> needs to be an object if there's only ever going to be one - once
> again 
> I think a functional rather than object-oriented style would be more 
> suitable to the problem. The main (only?) reason to have tests
> declared 
> as objects is for the auto-registration, beyond that it serves very 
> little purpose.

I agree that there's plenty of scope for simplification here (I think
the choice to go with halt-on-first-failure makes the runner class
redundant).  I'll have a go at simplifying things; I'll try to keep
auto-registration for now, but I'm in two minds about it.

> There are some inconsistent spellings of an end comment across the
> series:
> +}  // anon namespace
> +}  /* anon namespace.  */
> 
> I wasn't sure we were doing these at all, but it turns out the former
> is 
> the canonical one (with a single space).

Will fix.

Thanks

Dave

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 00/16] v6 of -fself-test/unit-testing patch
  2016-06-02 13:41                             ` David Malcolm
@ 2016-06-02 20:41                               ` David Malcolm
  2016-06-02 20:41                                 ` [PATCH 01/16] Core of selftest framework (v6) David Malcolm
                                                   ` (15 more replies)
  0 siblings, 16 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-02 20:41 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Given that we're now using an "abort on first failure" model, I
renamed all of the EXPECT_ macros to ASSERT_ (for consistency with
GTest).

As per Bernd's suggestions I eliminated the runner class and moved
to a more function-based rather than class-based approach.

At this point, the only reasons left for "class test" were
auto-registration, and giving names to tests.

So I tried removing it, and invoking tests manually.

I like the resulting code; it seems much simpler and clearer, with
very little "magic".

The following is an updated version of the patch kit that uses this
simpler approach.

In theory there's a slight risk to the manual-invocation approach.
If you forget a test within a file, the compiler tells you:

../../src/gcc/vec.c:204:1: warning: ‘void test_quick_push()’ defined but not used [-Wunused-function]

but if you forget to call the file from selftests.c, there's no warning.
I believe that adding a new test file will be a rare event, so this
kind of mistake will (I hope) be unlikely.
I've verified that the pass count before/after the change matches up.
By constrast, the auto-registration approach put us at the mercy of
the implementation of C++ global constructors, and I ran into at
least one surprise with that
( https://sourceware.org/bugzilla/show_bug.cgi?id=20152 ).

I've added the wide-int tests back.  These are parametrized by type,
and it was fairly easy to do this manually using templates once I
eliminated test registration.  I also added some new tests to
diagnostic-show-locus.c.

Although I'm posted this as a patch kit, it would be applied in one
commit: the initial patch makes reference to tests added in later
patches. I split it up so that each test file is in its own patch,
to make review easier (I hope).

As in v5, the tests are run in gcc/Makefile.in at each stage of a
bootstrap:
  $ grep "fself-test:" test/experiment/x86_64-pc-linux-gnu/build/make.log
  -fself-test: 621 pass(es) in 0.013000 seconds
  -fself-test: 621 pass(es) in 0.006000 seconds
  -fself-test: 621 pass(es) in 0.007000 seconds

Successfully bootstrapped&regression tested on x86_64-pc-linux-gnu.
A test against all configurations using contrib/config-list.mk is
in progress.

OK for trunk?

David Malcolm (16):
  Core of selftest framework (v6)
  diagnostic-show-locus.c: add selftests
  spellcheck.c: convert Levenshtein test from a plugin to a selftest
  bitmap.c: add selftests
  tree-cfg.c: add selftests
  et-forest.c: add selftests
  fold-const.c: add selftests
  Add function-tests.c
  gimple.c: add selftests
  Add hash-map-tests.c
  Add hash-set-tests.c
  input.c: add selftests
  Add rtl-tests.c
  tree.c: add selftests
  vec.c: add selftests
  wide-int.cc: add selftests

 gcc/Makefile.in                                  |  31 +-
 gcc/bitmap.c                                     | 110 ++++
 gcc/common.opt                                   |   4 +
 gcc/diagnostic-show-locus.c                      | 156 ++++++
 gcc/et-forest.c                                  | 112 ++++
 gcc/fold-const.c                                 |  75 +++
 gcc/function-tests.c                             | 639 +++++++++++++++++++++++
 gcc/gimple.c                                     | 119 +++++
 gcc/hash-map-tests.c                             |  88 ++++
 gcc/hash-set-tests.c                             |  64 +++
 gcc/input.c                                      | 112 ++++
 gcc/rtl-tests.c                                  | 108 ++++
 gcc/selftest-run-tests.c                         |  77 +++
 gcc/selftest.c                                   |  49 ++
 gcc/selftest.h                                   | 153 ++++++
 gcc/spellcheck.c                                 |  45 ++
 gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c |   9 -
 gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c |  64 ---
 gcc/testsuite/gcc.dg/plugin/plugin.exp           |   1 -
 gcc/toplev.c                                     |  26 +
 gcc/toplev.h                                     |   2 +
 gcc/tree-cfg.c                                   | 277 ++++++++++
 gcc/tree.c                                       |  60 +++
 gcc/vec.c                                        | 162 ++++++
 gcc/wide-int.cc                                  | 152 ++++++
 25 files changed, 2616 insertions(+), 79 deletions(-)
 create mode 100644 gcc/function-tests.c
 create mode 100644 gcc/hash-map-tests.c
 create mode 100644 gcc/hash-set-tests.c
 create mode 100644 gcc/rtl-tests.c
 create mode 100644 gcc/selftest-run-tests.c
 create mode 100644 gcc/selftest.c
 create mode 100644 gcc/selftest.h
 delete mode 100644 gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c
 delete mode 100644 gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c

-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 01/16] Core of selftest framework (v6)
  2016-06-02 20:41                               ` [PATCH 00/16] v6 of -fself-test/unit-testing patch David Malcolm
@ 2016-06-02 20:41                                 ` David Malcolm
  2016-06-02 23:21                                   ` Bernd Schmidt
  2016-06-02 20:41                                 ` [PATCH 10/16] Add hash-map-tests.c David Malcolm
                                                   ` (14 subsequent siblings)
  15 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2016-06-02 20:41 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

gcc/ChangeLog:
	* Makefile.in (OBJS): Add function-tests.o,
	hash-map-tests.o, hash-set-tests.o, rtl-tests.o,
	selftest-run-tests.o.
	(OBJS-libcommon): Add selftest.o.
	(OBJS-libcommon-target): Add selftest.o.
	(all.internal): Add "selftests".
	(all.cross): Likewise.
	(selftests): New phony target.
	(s-selftests): New target.
	(selftests-gdb): New phony target.
	(COLLECT2_OBJS): Add selftest.o.
	* common.opt (fself-test): New.
	* selftest-run-tests.c: New file.
	* selftest.c: New file.
	* selftest.h: New file.
	* toplev.c: Include selftest.h.
	(toplev::run_self_tests): New.
	(toplev::main): Handle -fself-test.
	* toplev.h (toplev::run_self_tests): New.
---
 gcc/Makefile.in          |  31 ++++++++--
 gcc/common.opt           |   4 ++
 gcc/selftest-run-tests.c |  76 ++++++++++++++++++++++++
 gcc/selftest.c           |  49 +++++++++++++++
 gcc/selftest.h           | 152 +++++++++++++++++++++++++++++++++++++++++++++++
 gcc/toplev.c             |  26 ++++++++
 gcc/toplev.h             |   2 +
 7 files changed, 335 insertions(+), 5 deletions(-)
 create mode 100644 gcc/selftest-run-tests.c
 create mode 100644 gcc/selftest.c
 create mode 100644 gcc/selftest.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 673f87d..2c5faa3 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1264,6 +1264,7 @@ OBJS = \
 	fold-const.o \
 	fold-const-call.o \
 	function.o \
+	function-tests.o \
 	fwprop.o \
 	gcc-rich-location.o \
 	gcse.o \
@@ -1299,6 +1300,8 @@ OBJS = \
 	graphite-sese-to-poly.o \
 	gtype-desc.o \
 	haifa-sched.o \
+	hash-map-tests.o \
+	hash-set-tests.o \
 	hsa.o \
 	hsa-gen.o \
 	hsa-regalloc.o \
@@ -1399,6 +1402,7 @@ OBJS = \
 	resource.o \
 	rtl-chkp.o \
 	rtl-error.o \
+	rtl-tests.o \
 	rtl.o \
 	rtlhash.o \
 	rtlanal.o \
@@ -1411,6 +1415,7 @@ OBJS = \
 	sel-sched-ir.o \
 	sel-sched-dump.o \
 	sel-sched.o \
+	selftest-run-tests.o \
 	sese.o \
 	shrink-wrap.o \
 	simplify-rtx.o \
@@ -1543,13 +1548,14 @@ OBJS = \
 # no target dependencies.
 OBJS-libcommon = diagnostic.o diagnostic-color.o diagnostic-show-locus.o \
 	pretty-print.o intl.o \
-	vec.o input.o version.o hash-table.o ggc-none.o memory-block.o
+	vec.o input.o version.o hash-table.o ggc-none.o memory-block.o \
+	selftest.o
 
 # Objects in libcommon-target.a, used by drivers and by the core
 # compiler and containing target-dependent code.
 OBJS-libcommon-target = $(common_out_object_file) prefix.o params.o \
 	opts.o opts-common.o options.o vec.o hooks.o common/common-targhooks.o \
-	hash-table.o file-find.o
+	hash-table.o file-find.o selftest.o
 
 # This lists all host objects for the front ends.
 ALL_HOST_FRONTEND_OBJS = $(foreach v,$(CONFIG_LANGUAGES),$($(v)_OBJS))
@@ -1816,10 +1822,10 @@ config.status: $(srcdir)/configure $(srcdir)/config.gcc
 quickstrap: all
 	cd $(toplevel_builddir) && $(MAKE) all-target-libgcc
 
-all.internal: start.encap rest.encap doc
+all.internal: start.encap rest.encap doc selftests
 # This is what to compile if making a cross-compiler.
 all.cross: native gcc-cross$(exeext) cpp$(exeext) specs \
-	libgcc-support lang.all.cross doc @GENINSRC@ srcextra
+	libgcc-support lang.all.cross doc selftests @GENINSRC@ srcextra
 # This is what must be made before installing GCC and converting libraries.
 start.encap: native xgcc$(exeext) cpp$(exeext) specs \
 	libgcc-support lang.start.encap @GENINSRC@ srcextra
@@ -1839,6 +1845,21 @@ endif
 # This does the things that can't be done on the host machine.
 rest.cross: specs
 
+# Run the selftests during the build once we have a driver and a cc1,
+# so that self-test failures are caught as early as possible.
+# Use "s-selftests" to ensure that we only run the selftests if the
+# driver or cc1 change.
+.PHONY: selftests
+selftests: s-selftests
+s-selftests: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs
+	$(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test
+	$(STAMP) $@
+
+# Convenience method for running selftests under gdb:
+.PHONY: selftests-gdb
+selftests-gdb: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs
+	$(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test -wrapper gdb,--args
+
 # Recompile all the language-independent object files.
 # This is used only if the user explicitly asks for it.
 compilations: $(BACKEND)
@@ -1986,7 +2007,7 @@ gcc-nm.c: gcc-ar.c
 	cp $^ $@
 
 COLLECT2_OBJS = collect2.o collect2-aix.o tlink.o vec.o ggc-none.o \
-  collect-utils.o file-find.o hash-table.o
+  collect-utils.o file-find.o hash-table.o selftest.o
 COLLECT2_LIBS = @COLLECT2_LIBS@
 collect2$(exeext): $(COLLECT2_OBJS) $(LIBDEPS)
 # Don't try modifying collect2 (aka ld) in place--it might be linking this.
diff --git a/gcc/common.opt b/gcc/common.opt
index 682cb41..10a10ed 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2057,6 +2057,10 @@ fselective-scheduling2
 Common Report Var(flag_selective_scheduling2) Optimization
 Run selective scheduling after reload.
 
+fself-test
+Common Undocumented Var(flag_self_test)
+Run self-tests.
+
 fsel-sched-pipelining
 Common Report Var(flag_sel_sched_pipelining) Init(0) Optimization
 Perform software pipelining of inner loops during selective scheduling.
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
new file mode 100644
index 0000000..4233351
--- /dev/null
+++ b/gcc/selftest-run-tests.c
@@ -0,0 +1,76 @@
+/* Implementation of selftests.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "selftest.h"
+
+/* This function needed to be split out from selftest.c as it references
+   tests from the whole source tree, and so is within
+   OBJS in Makefile.in, whereas selftest.o is within OBJS-libcommon.
+   This allows us to embed tests within files in OBJS-libcommon without
+   introducing a dependency on objects within OBJS.  */
+
+#if CHECKING_P
+
+/* Run all tests, aborting if any fail.  */
+
+void
+selftest::run_tests ()
+{
+  long start_time = get_run_time ();
+
+  /* Run all the tests, in hand-coded order of (approximate) dependencies:
+     run the tests for lowest-level code first.  */
+
+  /* Low-level data structures.  */
+  bitmap_c_tests ();
+  et_forest_c_tests ();
+  hash_map_tests_c_tests ();
+  hash_set_tests_c_tests ();
+  vec_c_tests ();
+
+  /* Mid-level data structures.  */
+  input_c_tests ();
+  tree_c_tests ();
+  gimple_c_tests ();
+  rtl_tests_c_tests ();
+
+  /* Higher-level tests, or for components that other selftests don't
+     rely on.  */
+  diagnostic_show_locus_c_tests ();
+  fold_const_c_tests ();
+  spellcheck_c_tests ();
+  tree_cfg_c_tests ();
+
+  /* This one relies on most of the above.  */
+  function_tests_c_tests ();
+
+  /* Finished running tests.  */
+  long finish_time = get_run_time ();
+  long elapsed_time = finish_time - start_time;
+
+  fprintf (stderr,
+	   "-fself-test: %i pass(es) in %ld.%06ld seconds\n",
+	   num_passes,
+	   elapsed_time / 1000000, elapsed_time % 1000000);
+}
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest.c b/gcc/selftest.c
new file mode 100644
index 0000000..cc921c8
--- /dev/null
+++ b/gcc/selftest.c
@@ -0,0 +1,49 @@
+/* A self-testing framework, for use by -fself-test.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+int selftest::num_passes;
+
+/* Record the successful outcome of some aspect of a test.  */
+
+void
+selftest::pass (const char */*file*/, int /*line*/, const char */*msg*/)
+{
+  num_passes++;
+}
+
+/* Report the failed outcome of some aspect of a test and abort.  */
+
+void
+selftest::fail (const char *file, int line, const char *msg)
+{
+  fprintf (stderr,
+	   "%s:%i: FAIL: %s\n",
+	   file, line, msg);
+  /* TODO: add calling function name as well?  */
+  abort ();
+}
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest.h b/gcc/selftest.h
new file mode 100644
index 0000000..2062a8b
--- /dev/null
+++ b/gcc/selftest.h
@@ -0,0 +1,152 @@
+/* A self-testing framework, for use by -fself-test.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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/>.  */
+
+#ifndef GCC_SELFTEST_H
+#define GCC_SELFTEST_H
+
+/* The selftest code should entirely disappear in a production
+   configuration, hence we guard all of it with #if CHECKING_P.  */
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* The entrypoint for running all tests.  */
+
+extern void run_tests ();
+
+/* Record the successful outcome of some aspect of the test.  */
+
+extern void pass (const char *file, int line, const char *msg);
+
+/* Report the failed outcome of some aspect of the test and abort.  */
+
+extern void fail (const char *file, int line, const char *msg);
+
+/* Declarations for specific families of tests (by source file), in
+   alphabetical order.  */
+extern void bitmap_c_tests ();
+extern void diagnostic_show_locus_c_tests ();
+extern void et_forest_c_tests ();
+extern void fold_const_c_tests ();
+extern void function_tests_c_tests ();
+extern void gimple_c_tests ();
+extern void hash_map_tests_c_tests ();
+extern void hash_set_tests_c_tests ();
+extern void input_c_tests ();
+extern void rtl_tests_c_tests ();
+extern void spellcheck_c_tests ();
+extern void tree_c_tests ();
+extern void tree_cfg_c_tests ();
+extern void vec_c_tests ();
+
+extern int num_passes;
+
+} /* end of namespace selftest.  */
+
+/* Macros for writing tests.  */
+
+/* Evaluate EXPR and coerce to bool, calling
+   ::selftest::pass if it is true,
+   ::selftest::fail if it false.  */
+
+#define ASSERT_TRUE(EXPR)				\
+  SELFTEST_BEGIN_STMT					\
+  const char *desc = "ASSERT_TRUE (" #EXPR ")";		\
+  bool actual = (EXPR);					\
+  if (actual)						\
+    ::selftest::pass (__FILE__, __LINE__, desc);	\
+  else							\
+    ::selftest::fail (__FILE__, __LINE__, desc);		\
+  SELFTEST_END_STMT
+
+/* Evaluate EXPR and coerce to bool, calling
+   ::selftest::pass if it is false,
+   ::selftest::fail if it true.  */
+
+#define ASSERT_FALSE(EXPR)					\
+  SELFTEST_BEGIN_STMT						\
+  const char *desc = "ASSERT_FALSE (" #EXPR ")";		\
+  bool actual = (EXPR);					\
+  if (actual)							\
+    ::selftest::fail (__FILE__, __LINE__, desc);				\
+  else								\
+    ::selftest::pass (__FILE__, __LINE__, desc);				\
+  SELFTEST_END_STMT
+
+/* Evaluate EXPECTED and ACTUAL and compare them with ==, calling
+   ::selftest::pass if they are equal,
+   ::selftest::fail if they are non-equal.  */
+
+#define ASSERT_EQ(EXPECTED, ACTUAL)			       \
+  SELFTEST_BEGIN_STMT					       \
+  const char *desc = "ASSERT_EQ (" #EXPECTED ", " #ACTUAL ")"; \
+  if ((EXPECTED) == (ACTUAL))				       \
+    ::selftest::pass (__FILE__, __LINE__, desc);			       \
+  else							       \
+    ::selftest::fail (__FILE__, __LINE__, desc);			       \
+  SELFTEST_END_STMT
+
+/* Evaluate EXPECTED and ACTUAL and compare them with !=, calling
+   ::selftest::pass if they are non-equal,
+   ::selftest::fail if they are equal.  */
+
+#define ASSERT_NE(EXPECTED, ACTUAL)			       \
+  SELFTEST_BEGIN_STMT					       \
+  const char *desc = "ASSERT_NE (" #EXPECTED ", " #ACTUAL ")"; \
+  if ((EXPECTED) != (ACTUAL))				       \
+    ::selftest::pass (__FILE__, __LINE__, desc);			       \
+  else							       \
+    ::selftest::fail (__FILE__, __LINE__, desc);			       \
+  SELFTEST_END_STMT
+
+/* Evaluate EXPECTED and ACTUAL and compare them with strcmp, calling
+   ::selftest::pass if they are equal,
+   ::selftest::fail if they are non-equal.  */
+
+#define ASSERT_STREQ(EXPECTED, ACTUAL)			       \
+  SELFTEST_BEGIN_STMT					       \
+  const char *desc = "ASSERT_STREQ (" #EXPECTED ", " #ACTUAL ")"; \
+  const char *expected_ = (EXPECTED);				  \
+  const char *actual_ = (ACTUAL);				  \
+  if (0 == strcmp (expected_, actual_))				  \
+    ::selftest::pass (__FILE__, __LINE__, desc);			       \
+  else							       \
+    ::selftest::fail (__FILE__, __LINE__, desc);			       \
+  SELFTEST_END_STMT
+
+/* Evaluate PRED1 (VAL1), calling ::selftest::pass if it is true,
+   ::selftest::fail if it is false.  */
+
+#define ASSERT_PRED1(PRED1, VAL1)			\
+  SELFTEST_BEGIN_STMT					\
+  const char *desc = "ASSERT_PRED1 (" #PRED1 ", " #VAL1 ")";	\
+  bool actual = (PRED1) (VAL1);				\
+  if (actual)						\
+    ::selftest::pass (__FILE__, __LINE__, desc);			\
+  else							\
+    ::selftest::fail (__FILE__, __LINE__, desc);			\
+  SELFTEST_END_STMT
+
+#define SELFTEST_BEGIN_STMT do {
+#define SELFTEST_END_STMT   } while (0)
+
+#endif /* #if CHECKING_P */
+
+#endif /* GCC_SELFTEST_H */
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 580c03a..795818a 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -87,6 +87,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "xcoffout.h"		/* Needed for external data declarations. */
 #endif
 
+#include "selftest.h"
+
 static void general_init (const char *, bool);
 static void do_compile ();
 static void process_options (void);
@@ -2031,6 +2033,27 @@ toplev::start_timevars ()
   timevar_start (TV_TOTAL);
 }
 
+/* Handle -fself-test.   */
+
+void
+toplev::run_self_tests ()
+{
+#if CHECKING_P
+  /* Reset some state.  */
+  input_location = UNKNOWN_LOCATION;
+  bitmap_obstack_initialize (NULL);
+
+  /* Run the tests; any failures will lead to an abort of the process.
+     Use "make selftests-gdb" to run under the debugger.  */
+  ::selftest::run_tests ();
+
+  /* Cleanup.  */
+  bitmap_obstack_release (NULL);
+#else
+  inform (UNKNOWN_LOCATION, "self-tests are not enabled in this build");
+#endif /* #if CHECKING_P */
+}
+
 /* Entry point of cc1, cc1plus, jc1, f771, etc.
    Exit code is FATAL_EXIT_CODE if can't open files or if there were
    any errors, or SUCCESS_EXIT_CODE if compilation succeeded.
@@ -2098,6 +2121,9 @@ toplev::main (int argc, char **argv)
   if (warningcount || errorcount || werrorcount)
     print_ignored_options ();
 
+  if (flag_self_test)
+    run_self_tests ();
+
   /* Invoke registered plugin callbacks if any.  Some plugins could
      emit some diagnostics here.  */
   invoke_plugin_callbacks (PLUGIN_FINISH, NULL);
diff --git a/gcc/toplev.h b/gcc/toplev.h
index 0beb06e..06923cf 100644
--- a/gcc/toplev.h
+++ b/gcc/toplev.h
@@ -42,6 +42,8 @@ private:
 
   void start_timevars ();
 
+  void run_self_tests ();
+
   bool m_use_TV_TOTAL;
   bool m_init_signals;
 };
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 10/16] Add hash-map-tests.c
  2016-06-02 20:41                               ` [PATCH 00/16] v6 of -fself-test/unit-testing patch David Malcolm
  2016-06-02 20:41                                 ` [PATCH 01/16] Core of selftest framework (v6) David Malcolm
@ 2016-06-02 20:41                                 ` David Malcolm
  2016-06-02 20:41                                 ` [PATCH 03/16] spellcheck.c: convert Levenshtein test from a plugin to a selftest David Malcolm
                                                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-02 20:41 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-hash-map.c):
 https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03301.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files is
> pre-approved.

This version moves the tests to gcc/hash-map-tests.c and
updates them to the new style.

gcc/ChangeLog:
	* hash-map-tests.c: New file.
---
 gcc/hash-map-tests.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 88 insertions(+)
 create mode 100644 gcc/hash-map-tests.c

diff --git a/gcc/hash-map-tests.c b/gcc/hash-map-tests.c
new file mode 100644
index 0000000..b2b9095
--- /dev/null
+++ b/gcc/hash-map-tests.c
@@ -0,0 +1,88 @@
+/* Unit tests for hash-map.h.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+static void
+test_map_of_strings_to_int ()
+{
+  hash_map <const char *, int> m;
+
+  const char *ostrich = "ostrich";
+  const char *elephant = "elephant";
+  const char *ant = "ant";
+  const char *spider = "spider";
+  const char *millipede = "Illacme plenipes";
+  const char *eric = "half a bee";
+
+  /* A fresh hash_map should be empty.  */
+  ASSERT_EQ (0, m.elements ());
+  ASSERT_EQ (NULL, m.get (ostrich));
+
+  /* Populate the hash_map.  */
+  ASSERT_EQ (false, m.put (ostrich, 2));
+  ASSERT_EQ (false, m.put (elephant, 4));
+  ASSERT_EQ (false, m.put (ant, 6));
+  ASSERT_EQ (false, m.put (spider, 8));
+  ASSERT_EQ (false, m.put (millipede, 750));
+  ASSERT_EQ (false, m.put (eric, 3));
+
+  /* Verify that we can recover the stored values.  */
+  ASSERT_EQ (6, m.elements ());
+  ASSERT_EQ (2, *m.get (ostrich));
+  ASSERT_EQ (4, *m.get (elephant));
+  ASSERT_EQ (6, *m.get (ant));
+  ASSERT_EQ (8, *m.get (spider));
+  ASSERT_EQ (750, *m.get (millipede));
+  ASSERT_EQ (3, *m.get (eric));
+
+  /* Verify removing an item.  */
+  m.remove (eric);
+  ASSERT_EQ (5, m.elements ());
+  ASSERT_EQ (NULL, m.get (eric));
+}
+
+namespace selftest {
+
+void
+hash_map_tests_c_tests ()
+{
+  test_map_of_strings_to_int ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 05/16] tree-cfg.c: add selftests
  2016-06-02 20:41                               ` [PATCH 00/16] v6 of -fself-test/unit-testing patch David Malcolm
                                                   ` (4 preceding siblings ...)
  2016-06-02 20:41                                 ` [PATCH 09/16] gimple.c: " David Malcolm
@ 2016-06-02 20:41                                 ` David Malcolm
  2016-06-02 20:41                                 ` [PATCH 04/16] bitmap.c: " David Malcolm
                                                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-02 20:41 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an older version of this:
https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03285.html
with:
> Unless there's a good reason, drop the presumably redundant tests
> and this is OK. Save preapprovald for these changes as the bitmap
> patch.

This version removes the redundant tests, moves the tests
from being in a new file to being in tree-cfg.c, and converts
them to the new style.

gcc/ChangeLog:
	* tree-cfg.c: Include "selftest.h".
	(push_fndecl): New function.
	(test_linear_chain): New function.
	(test_diamond): New function.
	(test_fully_connected): New function.
	(selftest::tree_cfg_c_tests): New function.
---
 gcc/tree-cfg.c | 277 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 277 insertions(+)

diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 6573702..dd2f7d2 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -58,6 +58,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-cfgcleanup.h"
 #include "gimplify.h"
 #include "attribs.h"
+#include "selftest.h"
 
 /* This file contains functions for building the Control Flow Graph (CFG)
    for a function tree.  */
@@ -9145,3 +9146,279 @@ gt_pch_nx (edge_def *e, gt_pointer_operator op, void *cookie)
     op (&(e->insns.r), cookie);
   op (&(block), cookie);
 }
+
+#if CHECKING_P
+
+/* Helper function for CFG selftests: create a dummy function decl
+   and push it as cfun.  */
+
+static tree
+push_fndecl (const char *name)
+{
+  tree fn_type = build_function_type_array (integer_type_node, /* return_type */
+					    0, NULL);
+  /* FIXME: this uses input_location: */
+  tree fndecl = build_fn_decl (name, fn_type);
+  tree retval = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+			    NULL_TREE, integer_type_node);
+  DECL_RESULT (fndecl) = retval;
+  push_struct_function (fndecl);
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  init_empty_tree_cfg_for_function (fun);
+  ASSERT_EQ (2, n_basic_blocks_for_fn (fun));
+  ASSERT_EQ (0, n_edges_for_fn (fun));
+  return fndecl;
+}
+
+/* These tests directly create CFGs.
+   Compare with the static fns within tree-cfg.c:
+     - build_gimple_cfg
+     - make_blocks: calls create_basic_block (seq, bb);
+     - make_edges.   */
+
+/* Verify a simple cfg of the form:
+     ENTRY -> A -> B -> C -> EXIT.  */
+
+static void
+test_linear_chain ()
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_test_linear_chain");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+
+  /* Create some empty blocks.  */
+  basic_block bb_a = create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun));
+  basic_block bb_b = create_empty_bb (bb_a);
+  basic_block bb_c = create_empty_bb (bb_b);
+
+  ASSERT_EQ (5, n_basic_blocks_for_fn (fun));
+  ASSERT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create some edges: a simple linear chain of BBs.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), bb_a, EDGE_FALLTHRU);
+  make_edge (bb_a, bb_b, 0);
+  make_edge (bb_b, bb_c, 0);
+  make_edge (bb_c, EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+
+  /* Verify the edges.  */
+  ASSERT_EQ (4, n_edges_for_fn (fun));
+  ASSERT_EQ (NULL, ENTRY_BLOCK_PTR_FOR_FN (fun)->preds);
+  ASSERT_EQ (1, ENTRY_BLOCK_PTR_FOR_FN (fun)->succs->length ());
+  ASSERT_EQ (1, bb_a->preds->length ());
+  ASSERT_EQ (1, bb_a->succs->length ());
+  ASSERT_EQ (1, bb_b->preds->length ());
+  ASSERT_EQ (1, bb_b->succs->length ());
+  ASSERT_EQ (1, bb_c->preds->length ());
+  ASSERT_EQ (1, bb_c->succs->length ());
+  ASSERT_EQ (1, EXIT_BLOCK_PTR_FOR_FN (fun)->preds->length ());
+  ASSERT_EQ (NULL, EXIT_BLOCK_PTR_FOR_FN (fun)->succs);
+
+  /* Verify the dominance information
+     Each BB in our simple chain should be dominated by the one before
+     it.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
+  ASSERT_EQ (bb_b, get_immediate_dominator (CDI_DOMINATORS, bb_c));
+  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
+  ASSERT_EQ (1, dom_by_b.length ());
+  ASSERT_EQ (bb_c, dom_by_b[0]);
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance: each BB in our chain is post-dominated
+     by the one after it.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  ASSERT_EQ (bb_b, get_immediate_dominator (CDI_POST_DOMINATORS, bb_a));
+  ASSERT_EQ (bb_c, get_immediate_dominator (CDI_POST_DOMINATORS, bb_b));
+  vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
+  ASSERT_EQ (1, postdom_by_b.length ());
+  ASSERT_EQ (bb_a, postdom_by_b[0]);
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+/* Verify a simple CFG of the form:
+     ENTRY
+       |
+       A
+      / \
+     /t  \f
+    B     C
+     \   /
+      \ /
+       D
+       |
+      EXIT.  */
+
+static void
+test_diamond ()
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_test_diamond");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+
+  /* Create some empty blocks.  */
+  basic_block bb_a = create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun));
+  basic_block bb_b = create_empty_bb (bb_a);
+  basic_block bb_c = create_empty_bb (bb_a);
+  basic_block bb_d = create_empty_bb (bb_b);
+
+  ASSERT_EQ (6, n_basic_blocks_for_fn (fun));
+  ASSERT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create the edges.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), bb_a, EDGE_FALLTHRU);
+  make_edge (bb_a, bb_b, EDGE_TRUE_VALUE);
+  make_edge (bb_a, bb_c, EDGE_FALSE_VALUE);
+  make_edge (bb_b, bb_d, 0);
+  make_edge (bb_c, bb_d, 0);
+  make_edge (bb_d, EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+
+  /* Verify the edges.  */
+  ASSERT_EQ (6, n_edges_for_fn (fun));
+  ASSERT_EQ (1, bb_a->preds->length ());
+  ASSERT_EQ (2, bb_a->succs->length ());
+  ASSERT_EQ (1, bb_b->preds->length ());
+  ASSERT_EQ (1, bb_b->succs->length ());
+  ASSERT_EQ (1, bb_c->preds->length ());
+  ASSERT_EQ (1, bb_c->succs->length ());
+  ASSERT_EQ (2, bb_d->preds->length ());
+  ASSERT_EQ (1, bb_d->succs->length ());
+
+  /* Verify the dominance information.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
+  ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_c));
+  ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_d));
+  vec<basic_block> dom_by_a = get_dominated_by (CDI_DOMINATORS, bb_a);
+  ASSERT_EQ (3, dom_by_a.length ()); /* B, C, D, in some order.  */
+  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
+  ASSERT_EQ (0, dom_by_b.length ());
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_a));
+  ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_b));
+  ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_c));
+  vec<basic_block> postdom_by_d = get_dominated_by (CDI_POST_DOMINATORS, bb_d);
+  ASSERT_EQ (3, postdom_by_d.length ()); /* A, B, C in some order.  */
+  vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
+  ASSERT_EQ (0, postdom_by_b.length ());
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+/* Verify that we can handle a CFG containing a "complete" aka
+   fully-connected subgraph (where A B C D below all have edges
+   pointing to each other node, also to themselves).
+   e.g.:
+     ENTRY  EXIT
+       |    ^
+       |   /
+       |  /
+       | /
+       V/
+       A<--->B
+       ^^   ^^
+       | \ / |
+       |  X  |
+       | / \ |
+       VV   VV
+       C<--->D
+*/
+
+static void
+test_fully_connected ()
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_fully_connected");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+
+  const int n = 4;
+
+  /* Create some empty blocks.  */
+  auto_vec <basic_block> subgraph_nodes;
+  for (int i = 0; i < n; i++)
+    subgraph_nodes.safe_push (create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun)));
+
+  ASSERT_EQ (n + 2, n_basic_blocks_for_fn (fun));
+  ASSERT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create the edges.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), subgraph_nodes[0], EDGE_FALLTHRU);
+  make_edge (subgraph_nodes[0], EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+  for (int i = 0; i < n; i++)
+    for (int j = 0; j < n; j++)
+      make_edge (subgraph_nodes[i], subgraph_nodes[j], 0);
+
+  /* Verify the edges.  */
+  ASSERT_EQ (2 + (n * n), n_edges_for_fn (fun));
+  /* The first one is linked to ENTRY/EXIT as well as itself and
+     everything else.  */
+  ASSERT_EQ (n + 1, subgraph_nodes[0]->preds->length ());
+  ASSERT_EQ (n + 1, subgraph_nodes[0]->succs->length ());
+  /* The other ones in the subgraph are linked to everything in
+     the subgraph (including themselves).  */
+  for (int i = 1; i < n; i++)
+    {
+      ASSERT_EQ (n, subgraph_nodes[i]->preds->length ());
+      ASSERT_EQ (n, subgraph_nodes[i]->succs->length ());
+    }
+
+  /* Verify the dominance information.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  /* The initial block in the subgraph should be dominated by ENTRY.  */
+  ASSERT_EQ (ENTRY_BLOCK_PTR_FOR_FN (fun),
+	     get_immediate_dominator (CDI_DOMINATORS,
+				      subgraph_nodes[0]));
+  /* Every other block in the subgraph should be dominated by the
+     initial block.  */
+  for (int i = 1; i < n; i++)
+    ASSERT_EQ (subgraph_nodes[0],
+	       get_immediate_dominator (CDI_DOMINATORS,
+					subgraph_nodes[i]));
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  /* The initial block in the subgraph should be postdominated by EXIT.  */
+  ASSERT_EQ (EXIT_BLOCK_PTR_FOR_FN (fun),
+	     get_immediate_dominator (CDI_POST_DOMINATORS,
+				      subgraph_nodes[0]));
+  /* Every other block in the subgraph should be postdominated by the
+     initial block, since that leads to EXIT.  */
+  for (int i = 1; i < n; i++)
+    ASSERT_EQ (subgraph_nodes[0],
+	       get_immediate_dominator (CDI_POST_DOMINATORS,
+					subgraph_nodes[i]));
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+namespace selftest {
+
+void
+tree_cfg_c_tests ()
+{
+  test_linear_chain ();
+  test_diamond ();
+  test_fully_connected ();
+}
+
+} // namespace selftest
+
+/* TODO: test the dominator/postdominator logic with various graphs/nodes:
+   - loop
+   - nested loops
+   - switch statement (a block with many out-edges)
+   - something that jumps to itself
+   - etc  */
+
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 04/16] bitmap.c: add selftests
  2016-06-02 20:41                               ` [PATCH 00/16] v6 of -fself-test/unit-testing patch David Malcolm
                                                   ` (5 preceding siblings ...)
  2016-06-02 20:41                                 ` [PATCH 05/16] tree-cfg.c: " David Malcolm
@ 2016-06-02 20:41                                 ` David Malcolm
  2016-06-02 20:57                                 ` [PATCH 08/16] Add function-tests.c David Malcolm
                                                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-02 20:41 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff pre-approved the plugin version of this (as a new
file unittests/test-bitmap.c):
https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03284.html
with:
> OK if/when prereqs are approved.  Minor twiddling if we end up moving it
> elsewhere or standardizing/reducing header files is pre-approved.

This version moves them to bitmap.c and converts them to
functions.

gcc/ChangeLog:
	* bitmap.c: Include "selftest.h".
	(test_gc_alloc): New function.
	(test_set_range): New function.
	(test_clear_bit_in_middle): New function.
	(test_copying): New function.
	(test_bitmap_single_bit_set_p): New function.
	(selftest::bitmap_c_tests): New function.
---
 gcc/bitmap.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 110 insertions(+)

diff --git a/gcc/bitmap.c b/gcc/bitmap.c
index 0c05512..21149e7 100644
--- a/gcc/bitmap.c
+++ b/gcc/bitmap.c
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "bitmap.h"
+#include "selftest.h"
 
 /* Memory allocation statistics purpose instance.  */
 mem_alloc_description<bitmap_usage> bitmap_mem_desc;
@@ -2162,5 +2163,114 @@ debug (const bitmap_head *ptr)
     fprintf (stderr, "<nil>\n");
 }
 
+#if CHECKING_P
+
+/* Selftests for bitmaps.  */
+
+/* Freshly-created bitmaps ought to be empty.  */
+
+static void
+test_gc_alloc ()
+{
+  bitmap b = bitmap_gc_alloc ();
+  ASSERT_TRUE (bitmap_empty_p (b));
+}
+
+/* Verify bitmap_set_range.  */
+
+static void
+test_set_range ()
+{
+  bitmap b = bitmap_gc_alloc ();
+  ASSERT_TRUE (bitmap_empty_p (b));
+
+  bitmap_set_range (b, 7, 5);
+  ASSERT_FALSE (bitmap_empty_p (b));
+  ASSERT_EQ (5, bitmap_count_bits (b));
+
+  /* Verify bitmap_bit_p at the boundaries.  */
+  ASSERT_FALSE (bitmap_bit_p (b, 6));
+  ASSERT_TRUE (bitmap_bit_p (b, 7));
+  ASSERT_TRUE (bitmap_bit_p (b, 11));
+  ASSERT_FALSE (bitmap_bit_p (b, 12));
+}
+
+/* Verify splitting a range into two pieces using bitmap_clear_bit.  */
+
+static void
+test_clear_bit_in_middle ()
+{
+  bitmap b = bitmap_gc_alloc ();
+
+  /* Set b to [100..200].  */
+  bitmap_set_range (b, 100, 100);
+  ASSERT_EQ (100, bitmap_count_bits (b));
+
+  /* Clear a bit in the middle.  */
+  bool changed = bitmap_clear_bit (b, 150);
+  ASSERT_TRUE (changed);
+  ASSERT_EQ (99, bitmap_count_bits (b));
+  ASSERT_TRUE (bitmap_bit_p (b, 149));
+  ASSERT_FALSE (bitmap_bit_p (b, 150));
+  ASSERT_TRUE (bitmap_bit_p (b, 151));
+}
+
+/* Verify bitmap_copy.  */
+
+static void
+test_copying ()
+{
+  bitmap src = bitmap_gc_alloc ();
+  bitmap_set_range (src, 40, 10);
+
+  bitmap dst = bitmap_gc_alloc ();
+  ASSERT_FALSE (bitmap_equal_p (src, dst));
+  bitmap_copy (dst, src);
+  ASSERT_TRUE (bitmap_equal_p (src, dst));
+
+  /* Verify that we can make them unequal again...  */
+  bitmap_set_range (src, 70, 5);
+  ASSERT_FALSE (bitmap_equal_p (src, dst));
+
+  /* ...and that changing src after the copy didn't affect
+     the other: */
+  ASSERT_FALSE (bitmap_bit_p (dst, 70));
+}
+
+/* Verify bitmap_single_bit_set_p.  */
+static void
+test_bitmap_single_bit_set_p ()
+{
+  bitmap b = bitmap_gc_alloc ();
+
+  ASSERT_FALSE (bitmap_single_bit_set_p (b));
+
+  bitmap_set_range (b, 42, 1);
+  ASSERT_TRUE (bitmap_single_bit_set_p (b));
+  ASSERT_EQ (42, bitmap_first_set_bit (b));
+
+  bitmap_set_range (b, 1066, 1);
+  ASSERT_FALSE (bitmap_single_bit_set_p (b));
+  ASSERT_EQ (42, bitmap_first_set_bit (b));
+
+  bitmap_clear_range (b, 0, 100);
+  ASSERT_TRUE (bitmap_single_bit_set_p (b));
+  ASSERT_EQ (1066, bitmap_first_set_bit (b));
+}
+
+namespace selftest {
+
+void
+bitmap_c_tests ()
+{
+  test_gc_alloc ();
+  test_set_range ();
+  test_clear_bit_in_middle ();
+  test_copying ();
+  test_bitmap_single_bit_set_p ();
+}
+
+} // namespace selftest
+#endif /* CHECKING_P */
 
 #include "gt-bitmap.h"
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 03/16] spellcheck.c: convert Levenshtein test from a plugin to a selftest
  2016-06-02 20:41                               ` [PATCH 00/16] v6 of -fself-test/unit-testing patch David Malcolm
  2016-06-02 20:41                                 ` [PATCH 01/16] Core of selftest framework (v6) David Malcolm
  2016-06-02 20:41                                 ` [PATCH 10/16] Add hash-map-tests.c David Malcolm
@ 2016-06-02 20:41                                 ` David Malcolm
  2016-06-02 20:41                                 ` [PATCH 02/16] diagnostic-show-locus.c: add selftests David Malcolm
                                                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-02 20:41 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

This is an example of converting one of our existing plugin-based
tests to run within -fself-test instead.

gcc/ChangeLog:
	* spellcheck.c: Include "selftest.h".
	(levenshtein_distance_unit_test_oneway): New function, adapted
	from testsuite/gcc.dg/plugin/levenshtein_plugin.c.
	(levenshtein_distance_unit_test): Likewise.
	(selftest::spellcheck_c_tests): Likewise.

gcc/testsuite/ChangeLog:
	* gcc.dg/plugin/levenshtein-test-1.c: Delete.
	* gcc.dg/plugin/levenshtein_plugin.c: Delete.
	* gcc.dg/plugin/plugin.exp (plugin_test_list): Remove the
	above.
---
 gcc/spellcheck.c                                 | 45 +++++++++++++++++
 gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c |  9 ----
 gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c | 64 ------------------------
 gcc/testsuite/gcc.dg/plugin/plugin.exp           |  1 -
 4 files changed, 45 insertions(+), 74 deletions(-)
 delete mode 100644 gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c
 delete mode 100644 gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c

diff --git a/gcc/spellcheck.c b/gcc/spellcheck.c
index e4e83a5..07c033a 100644
--- a/gcc/spellcheck.c
+++ b/gcc/spellcheck.c
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "tree.h"
 #include "spellcheck.h"
+#include "selftest.h"
 
 /* The Levenshtein distance is an "edit-distance": the minimal
    number of one-character insertions, removals or substitutions
@@ -165,3 +166,47 @@ find_closest_string (const char *target,
 
   return best_candidate;
 }
+
+#if CHECKING_P
+
+static void
+levenshtein_distance_unit_test_oneway (const char *a, const char *b,
+				       edit_distance_t expected)
+{
+  edit_distance_t actual = levenshtein_distance (a, b);
+  ASSERT_EQ (actual, expected);
+}
+
+static void
+levenshtein_distance_unit_test (const char *a, const char *b,
+				edit_distance_t expected)
+{
+  /* Run every test both ways to ensure it's symmetric.  */
+  levenshtein_distance_unit_test_oneway (a, b, expected);
+  levenshtein_distance_unit_test_oneway (b, a, expected);
+}
+
+namespace selftest {
+
+void
+spellcheck_c_tests ()
+{
+  levenshtein_distance_unit_test ("", "nonempty", strlen ("nonempty"));
+  levenshtein_distance_unit_test ("saturday", "sunday", 3);
+  levenshtein_distance_unit_test ("foo", "m_foo", 2);
+  levenshtein_distance_unit_test ("hello_world", "HelloWorld", 3);
+  levenshtein_distance_unit_test
+    ("the quick brown fox jumps over the lazy dog", "dog", 40);
+  levenshtein_distance_unit_test
+    ("the quick brown fox jumps over the lazy dog",
+     "the quick brown dog jumps over the lazy fox",
+     4);
+  levenshtein_distance_unit_test
+    ("Lorem ipsum dolor sit amet, consectetur adipiscing elit,",
+     "All your base are belong to us",
+     44);
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c b/gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c
deleted file mode 100644
index ac49992..0000000
--- a/gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c
+++ /dev/null
@@ -1,9 +0,0 @@
-/* Placeholder C source file for unit-testing gcc/spellcheck.c.  */
-/* { dg-do compile } */
-/* { dg-options "-O" } */
-
-int
-main (int argc, char **argv)
-{
-  return 0;
-}
diff --git a/gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c b/gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c
deleted file mode 100644
index 3e7dc78..0000000
--- a/gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Plugin for unittesting gcc/spellcheck.h.  */
-
-#include "config.h"
-#include "gcc-plugin.h"
-#include "system.h"
-#include "coretypes.h"
-#include "spellcheck.h"
-#include "diagnostic.h"
-
-int plugin_is_GPL_compatible;
-
-static void
-levenshtein_distance_unit_test_oneway (const char *a, const char *b,
-				       edit_distance_t expected)
-{
-  edit_distance_t actual = levenshtein_distance (a, b);
-  if (actual != expected)
-    error ("levenshtein_distance (\"%s\", \"%s\") : expected: %i got %i",
-	   a, b, expected, actual);
-}
-
-
-static void
-levenshtein_distance_unit_test (const char *a, const char *b,
-				edit_distance_t expected)
-{
-  /* Run every test both ways to ensure it's symmetric.  */
-  levenshtein_distance_unit_test_oneway (a, b, expected);
-  levenshtein_distance_unit_test_oneway (b, a, expected);
-}
-
-/* Callback handler for the PLUGIN_FINISH event; run
-   levenshtein_distance unit tests here.  */
-
-static void
-on_finish (void */*gcc_data*/, void */*user_data*/)
-{
-  levenshtein_distance_unit_test ("", "nonempty", strlen ("nonempty"));
-  levenshtein_distance_unit_test ("saturday", "sunday", 3);
-  levenshtein_distance_unit_test ("foo", "m_foo", 2);
-  levenshtein_distance_unit_test ("hello_world", "HelloWorld", 3);
-  levenshtein_distance_unit_test
-    ("the quick brown fox jumps over the lazy dog", "dog", 40);
-  levenshtein_distance_unit_test
-    ("the quick brown fox jumps over the lazy dog",
-     "the quick brown dog jumps over the lazy fox",
-     4);
-  levenshtein_distance_unit_test
-    ("Lorem ipsum dolor sit amet, consectetur adipiscing elit,",
-     "All your base are belong to us",
-     44);
-}
-
-int
-plugin_init (struct plugin_name_args *plugin_info,
-	     struct plugin_gcc_version */*version*/)
-{
-  register_callback (plugin_info->base_name,
-		     PLUGIN_FINISH,
-		     on_finish,
-		     NULL); /* void *user_data */
-
-  return 0;
-}
diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp
index fd1e98e..dfcdea2 100644
--- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
+++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
@@ -70,7 +70,6 @@ set plugin_test_list [list \
 	  diagnostic-test-expressions-1.c } \
     { diagnostic_plugin_show_trees.c \
 	  diagnostic-test-show-trees-1.c } \
-    { levenshtein_plugin.c levenshtein-test-1.c } \
     { location_overflow_plugin.c \
 	  location-overflow-test-1.c \
 	  location-overflow-test-2.c } \
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 02/16] diagnostic-show-locus.c: add selftests
  2016-06-02 20:41                               ` [PATCH 00/16] v6 of -fself-test/unit-testing patch David Malcolm
                                                   ` (2 preceding siblings ...)
  2016-06-02 20:41                                 ` [PATCH 03/16] spellcheck.c: convert Levenshtein test from a plugin to a selftest David Malcolm
@ 2016-06-02 20:41                                 ` David Malcolm
  2016-06-02 20:41                                 ` [PATCH 09/16] gimple.c: " David Malcolm
                                                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-02 20:41 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

gcc/ChangeLog:
	* diagnostic-show-locus.c: Include "selftest.h".
	(make_range): New function.
	(test_range_contains_point_for_single_point): New function.
	(test_range_contains_point_test_for_single_line): New function.
	(test_range_contains_point_for_multiple_lines): New function.
	(assert_eq): New function.
	(test_get_line_width_without_trailing_whitespace): New function.
	(selftest::diagnostic_show_locus_c_tests): New function.
---
 gcc/diagnostic-show-locus.c | 156 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 156 insertions(+)

diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
index eeccee5..38b424d 100644
--- a/gcc/diagnostic-show-locus.c
+++ b/gcc/diagnostic-show-locus.c
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "backtrace.h"
 #include "diagnostic.h"
 #include "diagnostic-color.h"
+#include "selftest.h"
 
 #ifdef HAVE_TERMIOS_H
 # include <termios.h>
@@ -442,6 +443,118 @@ layout_range::contains_point (int row, int column) const
   return column <= m_finish.m_column;
 }
 
+#if CHECKING_P
+
+/* A helper function for testing layout_range::contains_point.  */
+
+static layout_range
+make_range (int start_line, int start_col,
+	    int end_line, int end_col)
+{
+  const expanded_location start_exploc
+    = {"test.c", start_line, start_col, NULL, false};
+  const expanded_location finish_exploc
+    = {"test.c", end_line, end_col, NULL, false};
+  return layout_range (&start_exploc, &finish_exploc, false,
+		       &start_exploc);
+}
+
+/* Selftests for layout_range::contains_point.  */
+
+static void
+test_range_contains_point_for_single_point ()
+{
+  /* A range with start==end.  */
+  layout_range point = make_range (7, 10, 7, 10);
+
+  /* Before the line. */
+  ASSERT_FALSE (point.contains_point (6, 1));
+
+  /* On the line, but before start.  */
+  ASSERT_FALSE (point.contains_point (7, 9));
+
+  /* At the point.  */
+  ASSERT_TRUE (point.contains_point (7, 10));
+
+  /* On the line, after the point.  */
+  ASSERT_FALSE (point.contains_point (7, 11));
+
+  /* After the line.  */
+  ASSERT_FALSE (point.contains_point (8, 1));
+}
+
+static void
+test_range_contains_point_test_for_single_line ()
+{
+  /* The single-line example from above.  */
+  layout_range example_a = make_range (2, 22, 2, 38);
+
+  /* Before the line. */
+  ASSERT_FALSE (example_a.contains_point (1, 1));
+
+  /* On the line, but before start.  */
+  ASSERT_FALSE (example_a.contains_point (2, 21));
+
+  /* On the line, at the start.  */
+  ASSERT_TRUE (example_a.contains_point (2, 22));
+
+  /* On the line, within the range.  */
+  ASSERT_TRUE (example_a.contains_point (2, 23));
+
+  /* On the line, at the end.  */
+  ASSERT_TRUE (example_a.contains_point (2, 38));
+
+  /* On the line, after the end.  */
+  ASSERT_FALSE (example_a.contains_point (2, 39));
+
+  /* After the line.  */
+  ASSERT_FALSE (example_a.contains_point (2, 39));
+}
+
+static void
+test_range_contains_point_for_multiple_lines ()
+{
+  /* The multi-line example from above.  */
+  layout_range example_b = make_range (3, 14, 5, 8);
+
+  /* Before first line. */
+  ASSERT_FALSE (example_b.contains_point (1, 1));
+
+  /* On the first line, but before start.  */
+  ASSERT_FALSE (example_b.contains_point (3, 13));
+
+  /* At the start.  */
+  ASSERT_TRUE (example_b.contains_point (3, 14));
+
+  /* On the first line, within the range.  */
+  ASSERT_TRUE (example_b.contains_point (3, 15));
+
+  /* On an interior line.
+     The column number should not matter; try various boundary
+     values.  */
+  ASSERT_TRUE (example_b.contains_point (4, 1));
+  ASSERT_TRUE (example_b.contains_point (4, 7));
+  ASSERT_TRUE (example_b.contains_point (4, 8));
+  ASSERT_TRUE (example_b.contains_point (4, 9));
+  ASSERT_TRUE (example_b.contains_point (4, 13));
+  ASSERT_TRUE (example_b.contains_point (4, 14));
+  ASSERT_TRUE (example_b.contains_point (4, 15));
+
+  /* On the final line, before the end.  */
+  ASSERT_TRUE (example_b.contains_point (5, 7));
+
+  /* On the final line, at the end.  */
+  ASSERT_TRUE (example_b.contains_point (5, 8));
+
+  /* On the final line, after the end.  */
+  ASSERT_FALSE (example_b.contains_point (5, 9));
+
+  /* After the line.  */
+  ASSERT_FALSE (example_b.contains_point (6, 1));
+}
+
+#endif /* #if CHECKING_P */
+
 /* Given a source line LINE of length LINE_WIDTH, determine the width
    without any trailing whitespace.  */
 
@@ -465,6 +578,31 @@ get_line_width_without_trailing_whitespace (const char *line, int line_width)
   return result;
 }
 
+#if CHECKING_P
+
+/* A helper function for testing get_line_width_without_trailing_whitespace.  */
+
+static void
+assert_eq (const char *line, int expected_width)
+{
+  int actual_value
+    = get_line_width_without_trailing_whitespace (line, strlen (line));
+  ASSERT_EQ (actual_value, expected_width);
+}
+
+static void
+test_get_line_width_without_trailing_whitespace ()
+{
+  assert_eq ("", 0);
+  assert_eq (" ", 0);
+  assert_eq ("\t", 0);
+  assert_eq ("hello world", 11);
+  assert_eq ("hello world     ", 11);
+  assert_eq ("hello world     \t\t  ", 11);
+}
+
+#endif /* #if CHECKING_P */
+
 /* Helper function for layout's ctor, for sanitizing locations relative
    to the primary location within a diagnostic.
 
@@ -1171,3 +1309,21 @@ diagnostic_show_locus (diagnostic_context * context,
 
   pp_set_prefix (context->printer, saved_prefix);
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+void
+diagnostic_show_locus_c_tests ()
+{
+  test_range_contains_point_for_single_point ();
+  test_range_contains_point_test_for_single_line ();
+  test_range_contains_point_for_multiple_lines ();
+
+  test_get_line_width_without_trailing_whitespace ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 09/16] gimple.c: add selftests
  2016-06-02 20:41                               ` [PATCH 00/16] v6 of -fself-test/unit-testing patch David Malcolm
                                                   ` (3 preceding siblings ...)
  2016-06-02 20:41                                 ` [PATCH 02/16] diagnostic-show-locus.c: add selftests David Malcolm
@ 2016-06-02 20:41                                 ` David Malcolm
  2016-06-02 20:41                                 ` [PATCH 05/16] tree-cfg.c: " David Malcolm
                                                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-02 20:41 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-gimple.c):
https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03304.html

> OK if/when prereqs are approved. Minor twiddling if we end
> up moving it elsewhere or standardizing/reducing header files
> is pre-approved.

This version moves the tests into gimple.c and updates them to
the new style.

gcc/ChangeLog:
	* gimple.c: Include "selftest.h".
	Include "gimple-pretty-print.h".
	(verify_gimple_pp): New function.
	(test_assign_single): New function.
	(test_assign_binop): New function.
	(test_nop_stmt): New function.
	(test_return_stmt): New function.
	(test_return_without_value): New function.
	(selftest::gimple_c_tests): New function.
---
 gcc/gimple.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)

diff --git a/gcc/gimple.c b/gcc/gimple.c
index d822fab..c0a11a9 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-walk.h"
 #include "gimplify.h"
 #include "target.h"
+#include "selftest.h"
+#include "gimple-pretty-print.h"
 
 
 /* All the tuples have their operand vector (if present) at the very bottom
@@ -3016,3 +3018,120 @@ maybe_remove_unused_call_args (struct function *fn, gimple *stmt)
       update_stmt_fn (fn, stmt);
     }
 }
+
+#if CHECKING_P
+
+/* Selftests for core gimple structures.  */
+
+/* Helper function for selftests.  */
+
+static void
+verify_gimple_pp (const char *expected, gimple *stmt)
+{
+  pretty_printer pp;
+  pp_gimple_stmt_1 (&pp, stmt, 0 /* spc */, 0 /* flags */);
+  ASSERT_STREQ (expected, pp_formatted_text (&pp));
+}
+
+static void
+test_assign_single ()
+{
+  /* Build "tmp = 5;"  */
+  tree type = integer_type_node;
+  tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			 get_identifier ("tmp"),
+			 type);
+  tree rhs = build_int_cst (type, 5);
+  gassign *stmt = gimple_build_assign (lhs, rhs);
+  verify_gimple_pp ("tmp = 5;", stmt);
+
+  ASSERT_TRUE (is_gimple_assign (stmt));
+  ASSERT_EQ (lhs, gimple_assign_lhs (stmt));
+  ASSERT_EQ (lhs, gimple_get_lhs (stmt));
+  ASSERT_EQ (rhs, gimple_assign_rhs1 (stmt));
+  ASSERT_EQ (NULL, gimple_assign_rhs2 (stmt));
+  ASSERT_EQ (NULL, gimple_assign_rhs3 (stmt));
+  ASSERT_TRUE (gimple_assign_single_p (stmt));
+  ASSERT_EQ (INTEGER_CST, gimple_assign_rhs_code (stmt));
+}
+
+static void
+test_assign_binop ()
+{
+  /* Build "tmp = a * b;"  */
+  tree type = integer_type_node;
+  tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			 get_identifier ("tmp"),
+			 type);
+  tree a = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		       get_identifier ("a"),
+		       type);
+  tree b = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		       get_identifier ("b"),
+		       type);
+  gassign *stmt = gimple_build_assign (lhs, MULT_EXPR, a, b);
+  verify_gimple_pp ("tmp = a * b;", stmt);
+
+  ASSERT_TRUE (is_gimple_assign (stmt));
+  ASSERT_EQ (lhs, gimple_assign_lhs (stmt));
+  ASSERT_EQ (lhs, gimple_get_lhs (stmt));
+  ASSERT_EQ (a, gimple_assign_rhs1 (stmt));
+  ASSERT_EQ (b, gimple_assign_rhs2 (stmt));
+  ASSERT_EQ (NULL, gimple_assign_rhs3 (stmt));
+  ASSERT_FALSE (gimple_assign_single_p (stmt));
+  ASSERT_EQ (MULT_EXPR, gimple_assign_rhs_code (stmt));
+}
+
+static void
+test_nop_stmt ()
+{
+  gimple *stmt = gimple_build_nop ();
+  verify_gimple_pp ("GIMPLE_NOP", stmt);
+  ASSERT_EQ (GIMPLE_NOP, gimple_code (stmt));
+  ASSERT_EQ (NULL, gimple_get_lhs (stmt));
+  ASSERT_FALSE (gimple_assign_single_p (stmt));
+}
+
+static void
+test_return_stmt ()
+{
+  /* Build "return 7;"  */
+  tree type = integer_type_node;
+  tree val = build_int_cst (type, 7);
+  greturn *stmt = gimple_build_return (val);
+  verify_gimple_pp ("return 7;", stmt);
+
+  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt));
+  ASSERT_EQ (NULL, gimple_get_lhs (stmt));
+  ASSERT_EQ (val, gimple_return_retval (stmt));
+  ASSERT_FALSE (gimple_assign_single_p (stmt));
+}
+
+static void
+test_return_without_value ()
+{
+  greturn *stmt = gimple_build_return (NULL);
+  verify_gimple_pp ("return;", stmt);
+
+  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt));
+  ASSERT_EQ (NULL, gimple_get_lhs (stmt));
+  ASSERT_EQ (NULL, gimple_return_retval (stmt));
+  ASSERT_FALSE (gimple_assign_single_p (stmt));
+}
+
+namespace selftest {
+
+void
+gimple_c_tests ()
+{
+  test_assign_single ();
+  test_assign_binop ();
+  test_nop_stmt ();
+  test_return_stmt ();
+  test_return_without_value ();
+}
+
+} // namespace selftest
+
+
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 08/16] Add function-tests.c
  2016-06-02 20:41                               ` [PATCH 00/16] v6 of -fself-test/unit-testing patch David Malcolm
                                                   ` (6 preceding siblings ...)
  2016-06-02 20:41                                 ` [PATCH 04/16] bitmap.c: " David Malcolm
@ 2016-06-02 20:57                                 ` David Malcolm
  2016-06-02 20:58                                 ` [PATCH 14/16] tree.c: add selftests David Malcolm
                                                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-02 20:57 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-functions.c):
  https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03310.html
with:

> OK if/when prereqs are approved. Minor twiddling if we end up moving
> it elsewhere or standardizing/reducing header files is pre-approved.

gcc/ChangeLog:
	* function-tests.c: New file.
---
 gcc/function-tests.c | 639 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 639 insertions(+)
 create mode 100644 gcc/function-tests.c

diff --git a/gcc/function-tests.c b/gcc/function-tests.c
new file mode 100644
index 0000000..71e19e9
--- /dev/null
+++ b/gcc/function-tests.c
@@ -0,0 +1,639 @@
+/* Unit tests for function-handling.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "hard-reg-set.h"
+#include "input.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "gimple-expr.h"
+#include "toplev.h"
+#include "print-tree.h"
+#include "tree-iterator.h"
+#include "gimplify.h"
+#include "tree-cfg.h"
+#include "basic-block.h"
+#include "double-int.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "stmt.h"
+#include "hash-table.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "context.h"
+#include "hash-map.h"
+#include "plugin-api.h"
+#include "ipa-ref.h"
+#include "cgraph.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+/* Helper function for selftests of function-creation.  */
+
+static tree
+make_fndecl (tree return_type,
+	     const char *name,
+	     vec <tree> &param_types,
+	     bool is_variadic = false)
+{
+  tree fn_type;
+  if (is_variadic)
+    fn_type = build_varargs_function_type_array (return_type,
+						 param_types.length (),
+						 param_types.address ());
+  else
+    fn_type = build_function_type_array (return_type,
+					 param_types.length (),
+					 param_types.address ());
+  /* FIXME: this uses input_location: */
+  tree fndecl = build_fn_decl (name, fn_type);
+
+  return fndecl;
+}
+
+static void
+test_fndecl_int_void ()
+{
+  auto_vec <tree> param_types;
+  const char *name = "test_fndecl_int_void";
+  tree fndecl = make_fndecl (integer_type_node,
+			     name,
+			     param_types);
+  ASSERT_TRUE (fndecl != NULL);
+
+  /* Verify name of decl.  */
+  tree declname = DECL_NAME (fndecl);
+  ASSERT_TRUE (declname != NULL);
+  ASSERT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
+  /* We expect it to use a *copy* of the string we passed in.  */
+  const char *identifier_ptr = IDENTIFIER_POINTER (declname);
+  ASSERT_NE (name, identifier_ptr);
+  ASSERT_EQ (0, strcmp ("test_fndecl_int_void", identifier_ptr));
+
+  /* Verify type of fndecl.  */
+  ASSERT_EQ (FUNCTION_DECL, TREE_CODE (fndecl));
+  tree fntype = TREE_TYPE (fndecl);
+  ASSERT_EQ (FUNCTION_TYPE, TREE_CODE (fntype));
+
+  /* Verify return type.  */
+  ASSERT_EQ (integer_type_node, TREE_TYPE (fntype));
+
+  /* Verify "void" args.  */
+  tree argtypes = TYPE_ARG_TYPES (fntype);
+  ASSERT_EQ (TREE_LIST, TREE_CODE (argtypes));
+  ASSERT_EQ (void_type_node, TREE_VALUE (argtypes));
+  ASSERT_EQ (NULL, TREE_CHAIN (argtypes));
+}
+
+static void
+test_fndecl_float_intchar ()
+{
+  auto_vec <tree> param_types;
+  param_types.safe_push (integer_type_node);
+  param_types.safe_push (char_type_node);
+  const char *name = "test_fndecl_float_intchar";
+  tree fndecl = make_fndecl (float_type_node,
+			     name,
+			     param_types);
+  ASSERT_TRUE (fndecl != NULL);
+
+  /* Verify name of decl.  */
+  tree declname = DECL_NAME (fndecl);
+  ASSERT_TRUE (declname != NULL);
+  ASSERT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
+  /* We expect it to use a *copy* of the string we passed in.  */
+  const char *identifier_ptr = IDENTIFIER_POINTER (declname);
+  ASSERT_NE (name, identifier_ptr);
+  ASSERT_EQ (0, strcmp (name, identifier_ptr));
+
+  /* Verify type of fndecl.  */
+  ASSERT_EQ (FUNCTION_DECL, TREE_CODE (fndecl));
+  tree fntype = TREE_TYPE (fndecl);
+  ASSERT_EQ (FUNCTION_TYPE, TREE_CODE (fntype));
+
+  /* Verify return type.  */
+  ASSERT_EQ (float_type_node, TREE_TYPE (fntype));
+
+  /* Verify "(int, char)" args.  */
+  tree arg0 = TYPE_ARG_TYPES (fntype);
+  ASSERT_EQ (TREE_LIST, TREE_CODE (arg0));
+  ASSERT_EQ (integer_type_node, TREE_VALUE (arg0));
+  tree arg1 = TREE_CHAIN (arg0);
+  ASSERT_TRUE (arg1 != NULL);
+  ASSERT_EQ (TREE_LIST, TREE_CODE (arg1));
+  ASSERT_EQ (char_type_node, TREE_VALUE (arg1));
+  tree argterm = TREE_CHAIN (arg1);
+  ASSERT_TRUE (argterm != NULL);
+  ASSERT_EQ (TREE_LIST, TREE_CODE (argterm));
+  ASSERT_EQ (void_type_node, TREE_VALUE (argterm));
+  ASSERT_EQ (NULL, TREE_CHAIN (argterm));
+}
+
+/* The test cases using these helper functions take a trivial function:
+
+     int test_fn (void) { return 42; }
+
+   and test various conversions done to it:
+
+   - gimplification
+   - construction of the CFG
+   - conversion to SSA form
+   - expansion to RTL form
+
+   In avoid having one overlong test case, this is broken
+   up into separate test cases for each stage, with helper functions
+   to minimize code duplication.
+
+   Another approach would be to attempt to directly construct a function
+   in the appropriate representation at each stage, though presumably
+   that would exhibit different kinds of failure compared to this
+   approach.  */
+
+/* Construct this function:
+   int test_fn (void) { return 42; }
+   in generic tree form.  Return the fndecl.  */
+static tree
+build_trivial_generic_function ()
+{
+  auto_vec <tree> param_types;
+  tree fndecl = make_fndecl (integer_type_node,
+			     "test_fn",
+			     param_types);
+  ASSERT_TRUE (fndecl != NULL);
+
+  /* Populate the function.  */
+  tree retval = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+			    NULL_TREE, integer_type_node);
+  DECL_ARTIFICIAL (retval) = 1;
+  DECL_IGNORED_P (retval) = 1;
+  DECL_RESULT (fndecl) = retval;
+
+  /* Create a BIND_EXPR, and within it, a statement list.  */
+  tree stmt_list = alloc_stmt_list ();
+  tree_stmt_iterator stmt_iter = tsi_start (stmt_list);
+  tree block = make_node (BLOCK);
+  tree bind_expr =
+    build3 (BIND_EXPR, void_type_node, NULL, stmt_list, block);
+
+  tree modify_retval = build2 (MODIFY_EXPR,
+			       integer_type_node,
+			       retval,
+			       build_int_cst (integer_type_node, 42));
+  tree return_stmt = build1 (RETURN_EXPR,
+			     integer_type_node,
+			     modify_retval);
+  tsi_link_after (&stmt_iter, return_stmt, TSI_CONTINUE_LINKING);
+
+  DECL_INITIAL (fndecl) = block;
+
+  /* how to add to function? the following appears to be how to
+     set the body of a fndecl: */
+  DECL_SAVED_TREE(fndecl) = bind_expr;
+
+  /* Ensure that locals appear in the debuginfo.  */
+  BLOCK_VARS (block) = BIND_EXPR_VARS (bind_expr);
+
+  return fndecl;
+}
+
+/* Construct this function:
+     int test_fn (void) { return 42; }
+   in "high gimple" form.  Return the fndecl.  */
+static tree
+build_trivial_high_gimple_function ()
+{
+  /* Construct a trivial function, and gimplify it: */
+  tree fndecl = build_trivial_generic_function ();
+  gimplify_function_tree (fndecl);
+  return fndecl;
+}
+
+/* Build a CFG for a function in gimple form.  */
+static void
+build_cfg (tree fndecl)
+{
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  ASSERT_EQ (fndecl, fun->decl);
+
+  /* We first have to lower control flow; for our trivial test function
+     this gives us:
+	 test_fn ()
+	 {
+	   D.56 = 42;
+	   goto <D.57>;
+	   <D.57>:
+	   return D.56;
+	 }
+  */
+  gimple_opt_pass *lower_cf_pass = make_pass_lower_cf (g);
+  push_cfun (fun);
+  lower_cf_pass->execute (fun);
+  pop_cfun ();
+
+  /* We can now convert to CFG form; for our trivial test function this
+     gives us:
+	 test_fn ()
+	 {
+	   <bb 2>:
+	   D.56 = 42;
+	   return D.56;
+	 }
+  */
+  gimple_opt_pass *build_cfg_pass = make_pass_build_cfg (g);
+  push_cfun (fun);
+  build_cfg_pass->execute (fun);
+  pop_cfun ();
+}
+
+/* Convert a gimple+CFG function to SSA form.  */
+static void
+convert_to_ssa (tree fndecl)
+{
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  ASSERT_EQ (fndecl, fun->decl);
+
+  gimple_opt_pass *build_ssa_pass = make_pass_build_ssa (g);
+  push_cfun (fun);
+  build_ssa_pass->execute (fun);
+  pop_cfun ();
+}
+
+/* Assuming we have a simple 3-block CFG like this:
+     [ENTRY] -> [block2] -> [EXIT]
+   get the "real" basic block (block 2).  */
+static basic_block
+get_real_block (function *fun)
+{
+  ASSERT_TRUE (fun->cfg != NULL);
+  ASSERT_EQ (3, n_basic_blocks_for_fn (fun));
+  basic_block bb2 = (*fun->cfg->x_basic_block_info)[2];
+  ASSERT_TRUE (bb2 != NULL);
+  return bb2;
+}
+
+/* Verify that we have a simple 3-block CFG: the two "fake" ones, and
+   a "real" one:
+     [ENTRY] -> [block2] -> [EXIT].  */
+static void
+verify_three_block_cfg (function *fun)
+{
+  ASSERT_TRUE (fun->cfg != NULL);
+  ASSERT_EQ (3, n_basic_blocks_for_fn (fun));
+  ASSERT_EQ (2, n_edges_for_fn (fun));
+
+  /* The "fake" basic blocks.  */
+  basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (entry != NULL);
+  ASSERT_EQ (ENTRY_BLOCK, entry->index);
+
+  basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (exit != NULL);
+  ASSERT_EQ (EXIT_BLOCK, exit->index);
+
+  /* The "real" basic block.  */
+  basic_block bb2 = get_real_block (fun);
+  ASSERT_TRUE (bb2 != NULL);
+  ASSERT_EQ (2, bb2->index);
+
+  /* Verify connectivity.  */
+  ASSERT_EQ (NULL, entry->preds);
+  ASSERT_EQ (1, entry->succs->length ());
+
+  edge from_entry_to_bb2 = (*entry->succs)[0];
+  ASSERT_EQ (entry, from_entry_to_bb2->src);
+  ASSERT_EQ (bb2, from_entry_to_bb2->dest);
+
+  ASSERT_EQ (1, bb2->preds->length ());
+  ASSERT_EQ (from_entry_to_bb2, (*bb2->preds)[0]);
+  ASSERT_EQ (1, bb2->succs->length ());
+
+  edge from_bb2_to_exit = (*bb2->succs)[0];
+  ASSERT_EQ (bb2, from_bb2_to_exit->src);
+  ASSERT_EQ (exit, from_bb2_to_exit->dest);
+
+  ASSERT_EQ (1, exit->preds->length ());
+  ASSERT_EQ (from_bb2_to_exit, (*exit->preds)[0]);
+  ASSERT_EQ (NULL, exit->succs);
+}
+
+/* As above, but additionally verify the gimple statements are sane.  */
+static void
+verify_three_block_gimple_cfg (function *fun)
+{
+  verify_three_block_cfg (fun);
+
+  /* The "fake" basic blocks should be flagged as gimple, but with have no
+     statements.  */
+  basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (entry != NULL);
+  ASSERT_EQ (0, entry->flags & BB_RTL);
+  ASSERT_EQ (NULL, bb_seq (entry));
+
+  basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (exit != NULL);
+  ASSERT_EQ (0, entry->flags & BB_RTL);
+  ASSERT_EQ (NULL, bb_seq (exit));
+
+  /* The "real" basic block should be flagged as gimple, and have one
+     or more statements.  */
+  basic_block bb2 = get_real_block (fun);
+  ASSERT_TRUE (bb2 != NULL);
+  ASSERT_EQ (0, entry->flags & BB_RTL);
+  ASSERT_TRUE (bb_seq (bb2) != NULL);
+}
+
+/* As above, but additionally verify the RTL insns are sane.  */
+static void
+verify_three_block_rtl_cfg (function *fun)
+{
+  verify_three_block_cfg (fun);
+
+  /* The "fake" basic blocks should be flagged as RTL, but with no
+     insns.  */
+  basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (entry != NULL);
+  ASSERT_EQ (BB_RTL, entry->flags & BB_RTL);
+  ASSERT_EQ (NULL, BB_HEAD (entry));
+
+  basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (exit != NULL);
+  ASSERT_EQ (BB_RTL, entry->flags & BB_RTL);
+  ASSERT_EQ (NULL, BB_HEAD (exit));
+
+  /* The "real" basic block should be flagged as RTL, and have one
+     or more insns.  */
+  basic_block bb2 = get_real_block (fun);
+  ASSERT_TRUE (bb2 != NULL);
+  ASSERT_EQ (BB_RTL, entry->flags & BB_RTL);
+  ASSERT_TRUE (BB_HEAD (bb2) != NULL);
+}
+
+/* Test converting our trivial function:
+     int test_fn (void) { return 42; }
+   to gimple form.  */
+
+static void
+test_gimplification ()
+{
+  tree fndecl = build_trivial_generic_function ();
+
+  /* Convert to gimple: */
+  gimplify_function_tree (fndecl);
+
+  /* Verify that we got gimple out of it.  */
+
+  /* The function is now in GIMPLE form but the CFG has not been
+     built yet.  */
+
+  /* We should have a struct function for the decl.  */
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  ASSERT_EQ (fndecl, fun->decl);
+
+  /* We expect a GIMPLE_BIND, with two gimple statements within it:
+       tmp = 42;
+       return tmp;  */
+
+  gimple_seq seq_fn_body = gimple_body (fndecl);
+  ASSERT_TRUE (seq_fn_body != NULL);
+  gimple *bind_stmt = gimple_seq_first_stmt (seq_fn_body);
+  ASSERT_EQ (GIMPLE_BIND, gimple_code (bind_stmt));
+  ASSERT_EQ (NULL, bind_stmt->next);
+
+  gimple_seq seq_bind_body = gimple_bind_body (as_a <gbind *> (bind_stmt));
+
+  /* Verify that we have the 2 statements we expect.  */
+  ASSERT_TRUE (seq_bind_body != NULL);
+  gimple *stmt1 = gimple_seq_first_stmt (seq_bind_body);
+  ASSERT_TRUE (stmt1 != NULL);
+  ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt1));
+  gimple *stmt2 = stmt1->next;
+  ASSERT_TRUE (stmt2 != NULL);
+  ASSERT_EQ (stmt1, stmt2->prev);
+  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt2));
+}
+
+/* Test of building a CFG for a function in high gimple form.  */
+
+static void
+test_building_cfg ()
+{
+  /* Construct a trivial function, and gimplify it: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+
+  /* Build a CFG.  */
+  build_cfg (fndecl);
+
+  /* The CFG-building code constructs a 4-block cfg (with
+     ENTRY and EXIT):
+       test_fn ()
+       {
+         <bb 2>:
+	 D.65 = 42;
+
+	 <bb 3>:
+	 return D.65;
+       }
+     and then ought to merge blocks 2 and 3 in cleanup_tree_cfg.
+
+     Hence we should end up with a simple 3-block cfg, the two "fake" ones,
+     and a "real" one:
+       [ENTRY] -> [block2] -> [EXIT]
+     with code like this:
+	 test_fn ()
+	 {
+	   <bb 2>:
+	   D.56 = 42;
+	   return D.56;
+	 }
+  */
+  verify_three_block_gimple_cfg (fun);
+
+  /* Verify the statements within the "real" block.  */
+  basic_block bb2 = get_real_block (fun);
+  gimple *stmt_a = gimple_seq_first_stmt (bb_seq (bb2));
+  ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a));
+  gimple *stmt_b = stmt_a->next;
+  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt_b));
+  ASSERT_EQ (NULL, stmt_b->next);
+}
+
+/* Test of conversion of gimple to SSA form.  */
+static void
+test_conversion_to_ssa ()
+{
+  /* As above, construct a trivial function, gimplify it, and build a CFG: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  build_cfg (fndecl);
+
+  convert_to_ssa (fndecl);
+
+  verify_three_block_gimple_cfg (fun);
+
+  /* For out trivial test function we should now have something like
+     this:
+       test_fn ()
+       {
+	 <bb 2>:
+	 _1 = 42;
+	 return _1;
+       }
+  */
+  basic_block bb2 = get_real_block (fun);
+  gimple *stmt_a = gimple_seq_first_stmt (bb_seq (bb2));
+  ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a));
+
+  gimple *stmt_b = stmt_a->next;
+  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt_b));
+  ASSERT_EQ (NULL, stmt_b->next);
+
+  greturn *return_stmt = as_a <greturn *> (stmt_b);
+  ASSERT_EQ (SSA_NAME, TREE_CODE (gimple_return_retval (return_stmt)));
+}
+
+/* Test of expansion from gimple-ssa to RTL.  */
+
+static void
+test_expansion_to_rtl ()
+{
+  /* As above, construct a trivial function, gimplify it, build a CFG,
+     and convert to SSA: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  build_cfg (fndecl);
+  convert_to_ssa (fndecl);
+
+  /* We need a cgraph_node for it.  */
+  cgraph_node::get_create (fndecl);
+  /* Normally, cgraph_node::expand () would call
+     init_function_start (and a bunch of other stuff),
+     and invoke the expand pass, but it also runs
+     all of the other passes.  So just do the minimum
+     needed to get from gimple-SSA to RTL.  */
+  rtl_opt_pass *expand_pass = make_pass_expand (g);
+  push_cfun (fun);
+  init_function_start (fndecl);
+  expand_pass->execute (fun);
+  pop_cfun ();
+
+  /* On x86_64, I get this:
+       (note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+       (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
+       (insn 5 2 6 2 (set (reg:SI 87 [ D.59 ])
+			  (const_int 42 [0x2a])) -1 (nil))
+       (insn 6 5 10 2 (set (reg:SI 88 [ <retval> ])
+			   (reg:SI 87 [ D.59 ])) -1 (nil))
+       (insn 10 6 11 2 (set (reg/i:SI 0 ax)
+			    (reg:SI 88 [ <retval> ])) -1 (nil))
+       (insn 11 10 0 2 (use (reg/i:SI 0 ax)) -1 (nil))
+
+     On cr16-elf I get this:
+       (note 4 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+       (insn 2 4 3 2 (set (reg:SI 24)
+	    (reg/f:SI 16 virtual-incoming-args)) -1
+	  (nil))
+       (note 3 2 6 2 NOTE_INSN_FUNCTION_BEG)
+       (insn 6 3 7 2 (set (reg:HI 22 [ _1 ])
+	    (const_int 42 [0x2a])) -1
+	 (nil))
+       (insn 7 6 11 2 (set (reg:HI 23 [ <retval> ])
+	   (reg:HI 22 [ _1 ])) -1
+	 (nil))
+       (insn 11 7 12 2 (set (reg/i:HI 0 r0)
+	   (reg:HI 23 [ <retval> ])) -1
+	 (nil))
+       (insn 12 11 0 2 (use (reg/i:HI 0 r0)) -1
+	 (nil)).  */
+  verify_three_block_rtl_cfg (fun);
+
+  /* Verify as much of the RTL as we can whilst avoiding
+     target-specific behavior.  */
+  basic_block bb2 = get_real_block (fun);
+
+  /* Expect a NOTE_INSN_BASIC_BLOCK... */
+  rtx_insn *insn = BB_HEAD (bb2);
+  ASSERT_TRUE (insn != NULL);
+  ASSERT_EQ (NOTE, insn->code);
+  ASSERT_EQ (NOTE_INSN_BASIC_BLOCK, NOTE_KIND (insn));
+  ASSERT_EQ (bb2, NOTE_BASIC_BLOCK (insn));
+
+  /* ...etc; any further checks are likely to over-specify things
+     and run us into target dependencies.  */
+}
+
+namespace selftest {
+
+void
+function_tests_c_tests ()
+{
+  test_fndecl_int_void ();
+  test_fndecl_float_intchar ();
+  test_gimplification ();
+  test_building_cfg ();
+  test_conversion_to_ssa ();
+  test_expansion_to_rtl ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 14/16] tree.c: add selftests
  2016-06-02 20:41                               ` [PATCH 00/16] v6 of -fself-test/unit-testing patch David Malcolm
                                                   ` (7 preceding siblings ...)
  2016-06-02 20:57                                 ` [PATCH 08/16] Add function-tests.c David Malcolm
@ 2016-06-02 20:58                                 ` David Malcolm
  2016-06-02 21:03                                 ` [PATCH 12/16] input.c: " David Malcolm
                                                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-02 20:58 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-tree.c):
https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03303.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files is
> pre-approved.

gcc/ChangeLog:
	* tree.c: Include "selftest.h".
	(test_integer_constants): New function.
	(test_identifiers): New function.
	(test_labels): New function.
	(selftest::tree_c_tests): New function.
---
 gcc/tree.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

diff --git a/gcc/tree.c b/gcc/tree.c
index 5a1d167..ba22525 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -61,6 +61,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "print-tree.h"
 #include "ipa-utils.h"
+#include "selftest.h"
 
 /* Tree code classes.  */
 
@@ -14179,4 +14180,63 @@ combined_fn_name (combined_fn fn)
     return internal_fn_name (as_internal_fn (fn));
 }
 
+#if CHECKING_P
+
+/* Selftests for tree.  */
+
+/* Verify that integer constants are sane.  */
+
+static void
+test_integer_constants ()
+{
+  ASSERT_TRUE (integer_type_node != NULL);
+  ASSERT_TRUE (build_int_cst (integer_type_node, 0) != NULL);
+
+  tree type = integer_type_node;
+
+  tree zero = build_zero_cst (type);
+  ASSERT_EQ (INTEGER_CST, TREE_CODE (zero));
+  ASSERT_EQ (type, TREE_TYPE (zero));
+
+  tree one = build_int_cst (type, 1);
+  ASSERT_EQ (INTEGER_CST, TREE_CODE (one));
+  ASSERT_EQ (type, TREE_TYPE (zero));
+}
+
+/* Verify identifiers.  */
+
+static void
+test_identifiers ()
+{
+  tree identifier = get_identifier ("foo");
+  ASSERT_EQ (3, IDENTIFIER_LENGTH (identifier));
+  ASSERT_STREQ ("foo", IDENTIFIER_POINTER (identifier));
+}
+
+/* Verify LABEL_DECL.  */
+
+static void
+test_labels ()
+{
+  tree identifier = get_identifier ("err");
+  tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
+				identifier, void_type_node);
+  ASSERT_EQ (-1, LABEL_DECL_UID (label_decl));
+  ASSERT_FALSE (FORCED_LABEL (label_decl));
+}
+
+namespace selftest {
+
+void
+tree_c_tests ()
+{
+  test_integer_constants ();
+  test_identifiers ();
+  test_labels ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
+
 #include "gt-tree.h"
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 12/16] input.c: add selftests
  2016-06-02 20:41                               ` [PATCH 00/16] v6 of -fself-test/unit-testing patch David Malcolm
                                                   ` (8 preceding siblings ...)
  2016-06-02 20:58                                 ` [PATCH 14/16] tree.c: add selftests David Malcolm
@ 2016-06-02 21:03                                 ` David Malcolm
  2016-06-02 21:03                                 ` [PATCH 13/16] Add rtl-tests.c David Malcolm
                                                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-02 21:03 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff conditionally approved an earlier version of this (as
unittests/test-locations.c):
https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03307.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files is
> pre-approved.

gcc/ChangeLog:
	* input.c: Include "selftest.h".
	(assert_loceq): New function.
	(test_accessing_ordinary_linemaps): New function.
	(test_unknown_location): New function.
	(test_builtins): New function.
	(test_reading_source_line): New function.
	(selftest::input_c_tests): New function.
---
 gcc/input.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 112 insertions(+)

diff --git a/gcc/input.c b/gcc/input.c
index 61b1e44..b15b595 100644
--- a/gcc/input.c
+++ b/gcc/input.c
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "intl.h"
 #include "diagnostic-core.h"
+#include "selftest.h"
 
 /* This is a cache used by get_next_line to store the content of a
    file to be searched for file lines.  */
@@ -1136,3 +1137,114 @@ dump_location_info (FILE *stream)
   dump_labelled_location_range (stream, "AD-HOC LOCATIONS",
 				MAX_SOURCE_LOCATION + 1, UINT_MAX);
 }
+
+#if CHECKING_P
+
+/* Selftests of location handling.  */
+
+/* Verify the result of LOCATION_FILE/LOCATION_LINE/LOCATION_COLUMN
+   on LOC.  */
+
+static void
+assert_loceq (const char *exp_filename,
+	      int exp_linenum,
+	      int exp_colnum,
+	      location_t loc)
+{
+  ASSERT_STREQ (exp_filename, LOCATION_FILE (loc));
+  ASSERT_EQ (exp_linenum, LOCATION_LINE (loc));
+  ASSERT_EQ (exp_colnum, LOCATION_COLUMN (loc));
+}
+
+/* Verify basic operation of ordinary linemaps.  */
+
+static void
+test_accessing_ordinary_linemaps ()
+{
+  /* Build a simple linemap describing some locations. */
+  linemap_add (line_table, LC_ENTER, false, "foo.c", 0);
+
+  linemap_line_start (line_table, 1, 100);
+  location_t loc_a = linemap_position_for_column (line_table, 1);
+  location_t loc_b = linemap_position_for_column (line_table, 23);
+
+  linemap_line_start (line_table, 2, 100);
+  location_t loc_c = linemap_position_for_column (line_table, 1);
+  location_t loc_d = linemap_position_for_column (line_table, 17);
+
+  /* Example of a very long line.  */
+  linemap_line_start (line_table, 3, 2000);
+  location_t loc_e = linemap_position_for_column (line_table, 700);
+
+  linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+
+  /* Multiple files.  */
+  linemap_add (line_table, LC_ENTER, false, "bar.c", 0);
+  linemap_line_start (line_table, 1, 200);
+  location_t loc_f = linemap_position_for_column (line_table, 150);
+  linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+
+  /* Verify that we can recover the location info.  */
+  assert_loceq ("foo.c", 1, 1, loc_a);
+  assert_loceq ("foo.c", 1, 23, loc_b);
+  assert_loceq ("foo.c", 2, 1, loc_c);
+  assert_loceq ("foo.c", 2, 17, loc_d);
+  assert_loceq ("foo.c", 3, 700, loc_e);
+  assert_loceq ("bar.c", 1, 150, loc_f);
+
+  ASSERT_FALSE (is_location_from_builtin_token (loc_a));
+}
+
+static void
+test_unknown_location ()
+{
+  ASSERT_EQ (NULL, LOCATION_FILE (UNKNOWN_LOCATION));
+  ASSERT_EQ (0, LOCATION_LINE (UNKNOWN_LOCATION));
+  ASSERT_EQ (0, LOCATION_COLUMN (UNKNOWN_LOCATION));
+}
+
+static void
+test_builtins ()
+{
+  assert_loceq ("<built-in>", 0, 0, BUILTINS_LOCATION);
+  ASSERT_PRED1 (is_location_from_builtin_token, BUILTINS_LOCATION);
+}
+
+/* Verify reading of input files (e.g. for caret-based diagnostics.  */
+
+static void
+test_reading_source_line ()
+{
+  /* We will read *this* source file, using __FILE__.
+     Here is some specific text to read and test for:
+     The quick brown fox jumps over the lazy dog.  */
+  const int linenum_after_test_message = __LINE__;
+  const int linenum = linenum_after_test_message - 1;
+
+  int line_size;
+  const char *source_line = location_get_source_line (__FILE__, linenum, &line_size);
+  ASSERT_TRUE (source_line != NULL);
+  ASSERT_EQ (53, line_size);
+  if (!strncmp ("     The quick brown fox jumps over the lazy dog.  */",
+	       source_line, line_size))
+    ::selftest::pass (__FILE__, __LINE__,
+		      "source_line matched expected value");
+  else
+    ::selftest::fail (__FILE__, __LINE__,
+		      "source_line did not match expected value");
+}
+
+namespace selftest {
+
+void
+input_c_tests ()
+{
+  test_accessing_ordinary_linemaps ();
+  test_unknown_location ();
+  test_builtins ();
+  test_reading_source_line ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 13/16] Add rtl-tests.c
  2016-06-02 20:41                               ` [PATCH 00/16] v6 of -fself-test/unit-testing patch David Malcolm
                                                   ` (9 preceding siblings ...)
  2016-06-02 21:03                                 ` [PATCH 12/16] input.c: " David Malcolm
@ 2016-06-02 21:03                                 ` David Malcolm
  2016-06-02 21:03                                 ` [PATCH 16/16] wide-int.cc: add selftests David Malcolm
                                                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-02 21:03 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-rtl.c):
https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03302.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files is
>pre-approved.

gcc/ChangeLog:
	* rtl-tests.c: New file.
---
 gcc/rtl-tests.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 108 insertions(+)
 create mode 100644 gcc/rtl-tests.c

diff --git a/gcc/rtl-tests.c b/gcc/rtl-tests.c
new file mode 100644
index 0000000..a4ba79d
--- /dev/null
+++ b/gcc/rtl-tests.c
@@ -0,0 +1,108 @@
+/* Unit tests for RTL-handling.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "pretty-print.h"
+#include "cfgbuild.h"
+#include "print-rtl.h"
+#include "selftest.h"
+#include "function.h"
+#include "emit-rtl.h"
+
+#if CHECKING_P
+
+static void
+verify_print_pattern (const char *expected, rtx pat)
+{
+  pretty_printer pp;
+  print_pattern (&pp, pat, 1);
+  ASSERT_STREQ (expected, pp_formatted_text (&pp));
+}
+
+/* Unit testing of "single_set".  */
+static void
+test_single_set ()
+{
+  /* A label is not a SET.  */
+  ASSERT_EQ (NULL_RTX, single_set (gen_label_rtx ()));
+
+  /* An unconditional jump insn is a single SET.  */
+  rtx set_pc = gen_rtx_SET (pc_rtx,
+			    gen_rtx_LABEL_REF (VOIDmode,
+					       gen_label_rtx ()));
+  rtx_insn *jump_insn = emit_jump_insn (set_pc);
+  ASSERT_EQ (set_pc, single_set (jump_insn));
+
+  /* etc */
+}
+
+static void
+test_uncond_jump ()
+{
+  rtx_insn *label = gen_label_rtx ();
+  rtx jump_pat = gen_rtx_SET (pc_rtx,
+			      gen_rtx_LABEL_REF (VOIDmode,
+						 label));
+  ASSERT_EQ (SET, jump_pat->code);
+  ASSERT_EQ (LABEL_REF, SET_SRC (jump_pat)->code);
+  ASSERT_EQ (label, LABEL_REF_LABEL (SET_SRC (jump_pat)));
+  ASSERT_EQ (PC, SET_DEST (jump_pat)->code);
+
+  verify_print_pattern ("pc=L0", jump_pat);
+
+  rtx_insn *jump_insn = emit_jump_insn (jump_pat);
+  ASSERT_FALSE (any_condjump_p (jump_insn));
+  ASSERT_TRUE (any_uncondjump_p (jump_insn));
+  ASSERT_TRUE (pc_set (jump_insn));
+  ASSERT_TRUE (simplejump_p (jump_insn));
+  ASSERT_TRUE (onlyjump_p (jump_insn));
+  ASSERT_TRUE (control_flow_insn_p (jump_insn));
+}
+
+namespace selftest {
+
+void
+rtl_tests_c_tests ()
+{
+  test_single_set ();
+  test_uncond_jump ();
+
+  /* Purge state.  */
+  set_first_insn (NULL);
+  set_last_insn (NULL);
+}
+
+} // namespace selftest
+#endif /* #if CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 16/16] wide-int.cc: add selftests
  2016-06-02 20:41                               ` [PATCH 00/16] v6 of -fself-test/unit-testing patch David Malcolm
                                                   ` (10 preceding siblings ...)
  2016-06-02 21:03                                 ` [PATCH 13/16] Add rtl-tests.c David Malcolm
@ 2016-06-02 21:03                                 ` David Malcolm
  2016-06-02 21:06                                 ` [PATCH 15/16] vec.c: " David Malcolm
                                                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-02 21:03 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an early version of this:
https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03309.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files is
> pre-approved.

This version moves it to wide-int.cc and converts it to the new
style.  It's the only example so far of a type-parametrized test.

gcc/ChangeLog:
	* selftest-run-tests.c (selftest::run_tests): Add call
	to wide_int_cc_tests.
	* selftest.h (wide_int_cc_tests): New declaration.
	* wide-int.cc: Include selftest.h and wide-int-print.h.
	(from_int <wide_int>): New function.
	(from_int <offset_int>): New function.
	(from_int <widest_int>): New function.
	(assert_deceq): New function.
	(assert_hexeq): New function.
	(test_printing <VALUE_TYPE>): New function template.
	(test_ops <VALUE_TYPE>): New function template.
	(test_comparisons <VALUE_TYPE>): New function template.
	(run_all_wide_int_tests <VALUE_TYPE>): New function template.
	(selftest::wide_int_cc_tests): New function.
---
 gcc/selftest-run-tests.c |   1 +
 gcc/selftest.h           |   1 +
 gcc/wide-int.cc          | 152 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 154 insertions(+)

diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index 4233351..ab334aa 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -46,6 +46,7 @@ selftest::run_tests ()
   hash_map_tests_c_tests ();
   hash_set_tests_c_tests ();
   vec_c_tests ();
+  wide_int_cc_tests ();
 
   /* Mid-level data structures.  */
   input_c_tests ();
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 2062a8b..a1d3074 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -55,6 +55,7 @@ extern void spellcheck_c_tests ();
 extern void tree_c_tests ();
 extern void tree_cfg_c_tests ();
 extern void vec_c_tests ();
+extern void wide_int_cc_tests ();
 
 extern int num_passes;
 
diff --git a/gcc/wide-int.cc b/gcc/wide-int.cc
index 8648e7d..634dfb8 100644
--- a/gcc/wide-int.cc
+++ b/gcc/wide-int.cc
@@ -23,6 +23,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
+#include "selftest.h"
+#include "wide-int-print.h"
 
 
 #define HOST_BITS_PER_HALF_WIDE_INT 32
@@ -2144,3 +2146,153 @@ template void generic_wide_int <wide_int_ref_storage <false> >::dump () const;
 template void generic_wide_int <wide_int_ref_storage <true> >::dump () const;
 template void offset_int::dump () const;
 template void widest_int::dump () const;
+
+
+#if CHECKING_P
+
+/* Selftests for wide ints.  We run these multiple times, once per type.  */
+
+/* Helper function for building a test value.  */
+
+template <class VALUE_TYPE>
+static VALUE_TYPE
+from_int (int i);
+
+/* Specializations of the fixture for each wide-int type.  */
+
+template <>
+wide_int
+from_int (int i)
+{
+  return wi::shwi (i, 32);
+}
+
+template <>
+offset_int
+from_int (int i)
+{
+  return offset_int (i);
+}
+
+template <>
+widest_int
+from_int (int i)
+{
+  return widest_int (i);
+}
+
+/* Verify that print_dec (WI, ..., SGN) gives the expected string
+   representation (using base 10).  */
+
+static void
+assert_deceq (const char *expected, const wide_int_ref &wi, signop sgn)
+{
+  char buf[WIDE_INT_PRINT_BUFFER_SIZE];
+  print_dec (wi, buf, sgn);
+  ASSERT_STREQ (expected, buf);
+}
+
+/* Likewise for base 16.  */
+
+static void
+assert_hexeq (const char *expected, const wide_int_ref &wi)
+{
+  char buf[WIDE_INT_PRINT_BUFFER_SIZE];
+  print_hex (wi, buf);
+  ASSERT_STREQ (expected, buf);
+}
+
+/* Test cases.  */
+
+template <class VALUE_TYPE>
+static void
+test_printing ()
+{
+  VALUE_TYPE a = from_int<VALUE_TYPE> (42);
+  assert_deceq ("42", a, SIGNED);
+  assert_hexeq ("0x2a", a);
+}
+
+template <class VALUE_TYPE>
+static void
+test_ops ()
+{
+  VALUE_TYPE a = from_int<VALUE_TYPE> (7);
+  VALUE_TYPE b = from_int<VALUE_TYPE> (3);
+
+  /* Using functions.  */
+  assert_deceq ("-7", wi::neg (a), SIGNED);
+  assert_deceq ("10", wi::add (a, b), SIGNED);
+  assert_deceq ("4", wi::sub (a, b), SIGNED);
+  assert_deceq ("-4", wi::sub (b, a), SIGNED);
+  assert_deceq ("21", wi::mul (a, b), SIGNED);
+
+  /* Using operators.  */
+  assert_deceq ("-7", -a, SIGNED);
+  assert_deceq ("10", a + b, SIGNED);
+  assert_deceq ("4", a - b, SIGNED);
+  assert_deceq ("-4", b - a, SIGNED);
+  assert_deceq ("21", a * b, SIGNED);
+}
+
+template <class VALUE_TYPE>
+static void
+test_comparisons ()
+{
+  VALUE_TYPE a = from_int<VALUE_TYPE> (7);
+  VALUE_TYPE b = from_int<VALUE_TYPE> (3);
+
+  /* == */
+  ASSERT_TRUE (wi::eq_p (a, a));
+  ASSERT_FALSE (wi::eq_p (a, b));
+
+  /* != */
+  ASSERT_TRUE (wi::ne_p (a, b));
+  ASSERT_FALSE (wi::ne_p (a, a));
+
+  /* < */
+  ASSERT_FALSE (wi::lts_p (a, a));
+  ASSERT_FALSE (wi::lts_p (a, b));
+  ASSERT_TRUE (wi::lts_p (b, a));
+
+  /* <= */
+  ASSERT_TRUE (wi::les_p (a, a));
+  ASSERT_FALSE (wi::les_p (a, b));
+  ASSERT_TRUE (wi::les_p (b, a));
+
+  /* > */
+  ASSERT_FALSE (wi::gts_p (a, a));
+  ASSERT_TRUE (wi::gts_p (a, b));
+  ASSERT_FALSE (wi::gts_p (b, a));
+
+  /* >= */
+  ASSERT_TRUE (wi::ges_p (a, a));
+  ASSERT_TRUE (wi::ges_p (a, b));
+  ASSERT_FALSE (wi::ges_p (b, a));
+
+  /* comparison */
+  ASSERT_EQ (-1, wi::cmps (b, a));
+  ASSERT_EQ (0, wi::cmps (a, a));
+  ASSERT_EQ (1, wi::cmps (a, b));
+}
+
+template <class VALUE_TYPE>
+static void run_all_wide_int_tests ()
+{
+  test_printing <VALUE_TYPE> ();
+  test_ops <VALUE_TYPE> ();
+  test_comparisons <VALUE_TYPE> ();
+}
+
+namespace selftest {
+
+void
+wide_int_cc_tests ()
+{
+ run_all_wide_int_tests <wide_int> ();
+ run_all_wide_int_tests <offset_int> ();
+ run_all_wide_int_tests <widest_int> ();
+}
+
+} // namespace selftest
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 15/16] vec.c: add selftests
  2016-06-02 20:41                               ` [PATCH 00/16] v6 of -fself-test/unit-testing patch David Malcolm
                                                   ` (11 preceding siblings ...)
  2016-06-02 21:03                                 ` [PATCH 16/16] wide-int.cc: add selftests David Malcolm
@ 2016-06-02 21:06                                 ` David Malcolm
  2016-06-02 21:09                                 ` [PATCH 07/16] fold-const.c: " David Malcolm
                                                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-02 21:06 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-vec.c):
https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03308.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files is
> pre-approved.

gcc/ChangeLog:
	* vec.c: Include "selftest.h".
	(safe_push_range): New function.
	(test_quick_push): New function.
	(test_safe_push): New function.
	(test_truncate): New function.
	(test_safe_grow_cleared): New function.
	(test_safe_pop): New function.
	(test_safe_insert): New function.
	(test_ordered_remove): New function.
	(test_unordered_remove): New function.
	(test_block_remove): New function.
	(reverse_cmp): New function.
	(test_qsort): New function.
	(selftest::vec_c_tests): New function.c.
---
 gcc/vec.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 162 insertions(+)

diff --git a/gcc/vec.c b/gcc/vec.c
index a483d5b..b64a012 100644
--- a/gcc/vec.c
+++ b/gcc/vec.c
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "hash-table.h"
+#include "selftest.h"
 
 /* vNULL is an empty type with a template cast operation that returns
    a zero-initialized vec<T, A, L> instance.  Use this when you want
@@ -188,3 +189,164 @@ dump_vec_loc_statistics (void)
 {
   vec_mem_desc.dump (VEC_ORIGIN);
 }
+
+#ifndef GENERATOR_FILE
+#if CHECKING_P
+
+static void
+safe_push_range (vec <int>&v, int start, int limit)
+{
+  for (int i = start; i < limit; i++)
+    v.safe_push (i);
+}
+
+static void
+test_quick_push ()
+{
+  auto_vec <int> v;
+  ASSERT_EQ (0, v.length ());
+  v.reserve (3);
+  ASSERT_EQ (0, v.length ());
+  ASSERT_TRUE (v.space (3));
+  v.quick_push (5);
+  v.quick_push (6);
+  v.quick_push (7);
+  ASSERT_EQ (3, v.length ());
+  ASSERT_EQ (5, v[0]);
+  ASSERT_EQ (6, v[1]);
+  ASSERT_EQ (7, v[2]);
+}
+
+static void
+test_safe_push ()
+{
+  auto_vec <int> v;
+  ASSERT_EQ (0, v.length ());
+  v.safe_push (5);
+  v.safe_push (6);
+  v.safe_push (7);
+  ASSERT_EQ (3, v.length ());
+  ASSERT_EQ (5, v[0]);
+  ASSERT_EQ (6, v[1]);
+  ASSERT_EQ (7, v[2]);
+}
+
+static void
+test_truncate ()
+{
+  auto_vec <int> v;
+  ASSERT_EQ (0, v.length ());
+  safe_push_range (v, 0, 10);
+  ASSERT_EQ (10, v.length ());
+
+  v.truncate (5);
+  ASSERT_EQ (5, v.length ());
+}
+
+static void
+test_safe_grow_cleared ()
+{
+  auto_vec <int> v;
+  ASSERT_EQ (0, v.length ());
+  v.safe_grow_cleared (50);
+  ASSERT_EQ (50, v.length ());
+  ASSERT_EQ (0, v[0]);
+  ASSERT_EQ (0, v[49]);
+}
+
+static void
+test_safe_pop ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 5, 20);
+  ASSERT_EQ (15, v.length ());
+
+  int last = v.pop ();
+  ASSERT_EQ (19, last);
+  ASSERT_EQ (14, v.length ());
+}
+
+static void
+test_safe_insert ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.safe_insert (5, 42);
+  ASSERT_EQ (4, v[4]);
+  ASSERT_EQ (42, v[5]);
+  ASSERT_EQ (5, v[6]);
+  ASSERT_EQ (11, v.length ());
+}
+
+static void
+test_ordered_remove ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.ordered_remove (5);
+  ASSERT_EQ (4, v[4]);
+  ASSERT_EQ (6, v[5]);
+  ASSERT_EQ (9, v.length ());
+}
+
+static void
+test_unordered_remove ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.unordered_remove (5);
+  ASSERT_EQ (9, v.length ());
+}
+
+static void
+test_block_remove ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.block_remove (5, 3);
+  ASSERT_EQ (3, v[3]);
+  ASSERT_EQ (4, v[4]);
+  ASSERT_EQ (8, v[5]);
+  ASSERT_EQ (9, v[6]);
+  ASSERT_EQ (7, v.length ());
+}
+
+static int reverse_cmp (const void *p_i, const void *p_j)
+{
+  return *(const int *)p_j - *(const int *)p_i;
+}
+
+static void
+test_qsort ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.qsort (reverse_cmp);
+  ASSERT_EQ (9, v[0]);
+  ASSERT_EQ (8, v[1]);
+  ASSERT_EQ (1, v[8]);
+  ASSERT_EQ (0, v[9]);
+  ASSERT_EQ (10, v.length ());
+}
+
+namespace selftest {
+
+void
+vec_c_tests ()
+{
+  test_quick_push ();
+  test_safe_push ();
+  test_truncate ();
+  test_safe_grow_cleared ();
+  test_safe_pop ();
+  test_safe_insert ();
+  test_ordered_remove ();
+  test_unordered_remove ();
+  test_block_remove ();
+  test_qsort ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
+#endif /* #ifndef GENERATOR_FILE */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 07/16] fold-const.c: add selftests
  2016-06-02 20:41                               ` [PATCH 00/16] v6 of -fself-test/unit-testing patch David Malcolm
                                                   ` (12 preceding siblings ...)
  2016-06-02 21:06                                 ` [PATCH 15/16] vec.c: " David Malcolm
@ 2016-06-02 21:09                                 ` David Malcolm
  2016-06-02 21:09                                 ` [PATCH 11/16] Add hash-set-tests.c David Malcolm
  2016-06-02 21:09                                 ` [PATCH 06/16] et-forest.c: add selftests David Malcolm
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-02 21:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an older version of this (as a separate
unittests/test-folding.c):
https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03305.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files
> is pre-approved.

gcc/ChangeLog:
	* fold-const.c: Include "selftest.h".
	(assert_binop_folds_to_const): New function.
	(assert_binop_folds_to_nonlvalue): New function.
	(test_arithmetic_folding): New function.
	(selftest::fold_const_c_tests): New function.
---
 gcc/fold-const.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)

diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 8a7c93e..dd8cdab 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -76,6 +76,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "case-cfn-macros.h"
 #include "stringpool.h"
 #include "tree-ssanames.h"
+#include "selftest.h"
 
 #ifndef LOAD_EXTEND_OP
 #define LOAD_EXTEND_OP(M) UNKNOWN
@@ -14455,3 +14456,77 @@ c_getstr (tree src)
 
   return TREE_STRING_POINTER (src) + tree_to_uhwi (offset_node);
 }
+
+#if CHECKING_P
+
+/* Helper functions for writing tests of folding trees.  */
+
+/* Verify that the binary op (LHS CODE RHS) folds to CONSTANT.  */
+
+static void
+assert_binop_folds_to_const (tree lhs, enum tree_code code, tree rhs,
+			     tree constant)
+{
+  ASSERT_EQ (constant, fold_build2 (code, TREE_TYPE (lhs), lhs, rhs));
+}
+
+/* Verify that the binary op (LHS CODE RHS) folds to an NON_LVALUE_EXPR
+   wrapping WRAPPED_EXPR.  */
+
+static void
+assert_binop_folds_to_nonlvalue (tree lhs, enum tree_code code, tree rhs,
+				 tree wrapped_expr)
+{
+  tree result = fold_build2 (code, TREE_TYPE (lhs), lhs, rhs);
+  ASSERT_NE (wrapped_expr, result);
+  ASSERT_EQ (NON_LVALUE_EXPR, TREE_CODE (result));
+  ASSERT_EQ (wrapped_expr, TREE_OPERAND (result, 0));
+}
+
+static void
+test_arithmetic_folding ()
+{
+  tree type = integer_type_node;
+  tree x = create_tmp_var_raw (type, "x");
+  tree zero = build_zero_cst (type);
+  tree one = build_int_cst (type, 1);
+
+  /* Addition.  */
+  /* 1 <-- (0 + 1) */
+  assert_binop_folds_to_const (zero, PLUS_EXPR, one,
+			       one);
+  assert_binop_folds_to_const (one, PLUS_EXPR, zero,
+			       one);
+
+  /* (nonlvalue)x <-- (x + 0) */
+  assert_binop_folds_to_nonlvalue (x, PLUS_EXPR, zero,
+				   x);
+
+  /* Subtraction.  */
+  /* 0 <-- (x - x) */
+  assert_binop_folds_to_const (x, MINUS_EXPR, x,
+			       zero);
+  assert_binop_folds_to_nonlvalue (x, MINUS_EXPR, zero,
+				   x);
+
+  /* Multiplication.  */
+  /* 0 <-- (x * 0) */
+  assert_binop_folds_to_const (x, MULT_EXPR, zero,
+			       zero);
+
+  /* (nonlvalue)x <-- (x * 1) */
+  assert_binop_folds_to_nonlvalue (x, MULT_EXPR, one,
+				   x);
+}
+
+namespace selftest {
+
+void
+fold_const_c_tests ()
+{
+  test_arithmetic_folding ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 11/16] Add hash-set-tests.c
  2016-06-02 20:41                               ` [PATCH 00/16] v6 of -fself-test/unit-testing patch David Malcolm
                                                   ` (13 preceding siblings ...)
  2016-06-02 21:09                                 ` [PATCH 07/16] fold-const.c: " David Malcolm
@ 2016-06-02 21:09                                 ` David Malcolm
  2016-06-02 21:09                                 ` [PATCH 06/16] et-forest.c: add selftests David Malcolm
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-02 21:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this (as
unittests/test-hash-set.c):
 https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03300.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files is
> pre-approved.

This version moves the tests to gcc/hash-set-tests.c and updates
them to the new style.

gcc/ChangeLog:
	* hash-set-tests.c: New file.
---
 gcc/hash-set-tests.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)
 create mode 100644 gcc/hash-set-tests.c

diff --git a/gcc/hash-set-tests.c b/gcc/hash-set-tests.c
new file mode 100644
index 0000000..cdca42a
--- /dev/null
+++ b/gcc/hash-set-tests.c
@@ -0,0 +1,64 @@
+/* Unit tests for hash-set.h.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+static void
+test_set_of_strings ()
+{
+  hash_set <const char *> s;
+  ASSERT_EQ (0, s.elements ());
+
+  const char *red = "red";
+  const char *green = "green";
+  const char *blue = "blue";
+
+  ASSERT_EQ (false, s.contains (red));
+
+  /* Populate the hash_set.  */
+  ASSERT_EQ (false, s.add (red));
+  ASSERT_EQ (false, s.add (green));
+  ASSERT_EQ (false, s.add (blue));
+
+  /* Verify that the values are now within the set.  */
+  ASSERT_EQ (true, s.contains (red));
+  ASSERT_EQ (true, s.contains (green));
+  ASSERT_EQ (true, s.contains (blue));
+}
+
+namespace selftest {
+
+void
+hash_set_tests_c_tests ()
+{
+  test_set_of_strings ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH 06/16] et-forest.c: add selftests
  2016-06-02 20:41                               ` [PATCH 00/16] v6 of -fself-test/unit-testing patch David Malcolm
                                                   ` (14 preceding siblings ...)
  2016-06-02 21:09                                 ` [PATCH 11/16] Add hash-set-tests.c David Malcolm
@ 2016-06-02 21:09                                 ` David Malcolm
  15 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-02 21:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

Jeff approved an earlier version of this:
https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03295.html
> OK if/when prereqs are approved. Minor twiddling if we end up
> moving it elsewhere or standardizing/reducing header files
> is pre-approved.

This version has been updated to the new style.

gcc/ChangeLog:
	* et-forest.c: Include "selftest.h".
	(test_single_node): New function.
	(test_simple_tree): New function.
	(test_disconnected_nodes): New function.
	(selftest::et_forest_c_tests): New function.
---
 gcc/et-forest.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 112 insertions(+)

diff --git a/gcc/et-forest.c b/gcc/et-forest.c
index cd36752..679abee 100644
--- a/gcc/et-forest.c
+++ b/gcc/et-forest.c
@@ -27,6 +27,7 @@ License along with libiberty; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "alloc-pool.h"
 #include "et-forest.h"
+#include "selftest.h"
 
 /* We do not enable this with CHECKING_P, since it is awfully slow.  */
 #undef DEBUG_ET
@@ -764,3 +765,114 @@ et_root (struct et_node *node)
 
   return r->of;
 }
+
+#if CHECKING_P
+
+/* Selftests for et-forest.c.  */
+
+static void
+test_single_node ()
+{
+  void *test_data = (void *)0xcafebabe;
+
+  et_node *n = et_new_tree (test_data);
+  ASSERT_EQ (n->data, test_data);
+  ASSERT_EQ (n, et_root (n));
+  et_free_tree (n);
+}
+
+/* Test of this tree:
+       a
+      / \
+     /   \
+    b     c
+   / \    |
+  d   e   f.  */
+
+static void
+test_simple_tree ()
+{
+  et_node *a = et_new_tree (NULL);
+  et_node *b = et_new_tree (NULL);
+  et_node *c = et_new_tree (NULL);
+  et_node *d = et_new_tree (NULL);
+  et_node *e = et_new_tree (NULL);
+  et_node *f = et_new_tree (NULL);
+
+  et_set_father (b, a);
+  et_set_father (c, a);
+  et_set_father (d, b);
+  et_set_father (e, b);
+  et_set_father (f, c);
+
+  ASSERT_TRUE (et_below (a, a));
+  ASSERT_TRUE (et_below (b, a));
+  ASSERT_TRUE (et_below (c, a));
+  ASSERT_TRUE (et_below (d, a));
+  ASSERT_TRUE (et_below (e, a));
+  ASSERT_TRUE (et_below (f, a));
+
+  ASSERT_FALSE (et_below (a, b));
+  ASSERT_TRUE (et_below (b, b));
+  ASSERT_FALSE (et_below (c, b));
+  ASSERT_TRUE (et_below (d, b));
+  ASSERT_TRUE (et_below (e, b));
+  ASSERT_FALSE (et_below (f, b));
+
+  ASSERT_FALSE (et_below (a, c));
+  ASSERT_FALSE (et_below (b, c));
+  ASSERT_TRUE (et_below (c, c));
+  ASSERT_FALSE (et_below (d, c));
+  ASSERT_FALSE (et_below (e, c));
+  ASSERT_TRUE (et_below (f, c));
+
+  ASSERT_FALSE (et_below (a, d));
+  ASSERT_FALSE (et_below (b, d));
+  ASSERT_FALSE (et_below (c, d));
+  ASSERT_TRUE (et_below (d, d));
+  ASSERT_FALSE (et_below (e, d));
+  ASSERT_FALSE (et_below (f, d));
+
+  ASSERT_FALSE (et_below (a, e));
+  ASSERT_FALSE (et_below (b, e));
+  ASSERT_FALSE (et_below (c, e));
+  ASSERT_FALSE (et_below (d, e));
+  ASSERT_TRUE (et_below (e, e));
+  ASSERT_FALSE (et_below (f, e));
+
+  ASSERT_FALSE (et_below (a, f));
+  ASSERT_FALSE (et_below (b, f));
+  ASSERT_FALSE (et_below (c, f));
+  ASSERT_FALSE (et_below (d, f));
+  ASSERT_FALSE (et_below (e, f));
+  ASSERT_TRUE (et_below (f, f));
+
+  et_free_tree_force (a);
+}
+
+static void
+test_disconnected_nodes ()
+{
+  et_node *a = et_new_tree (NULL);
+  et_node *b = et_new_tree (NULL);
+
+  ASSERT_FALSE (et_below (a, b));
+  ASSERT_FALSE (et_below (b, a));
+
+  et_free_tree (a);
+  et_free_tree (b);
+}
+
+namespace selftest {
+
+void
+et_forest_c_tests ()
+{
+  test_single_node ();
+  test_simple_tree ();
+  test_disconnected_nodes ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH 01/16] Core of selftest framework (v6)
  2016-06-02 20:41                                 ` [PATCH 01/16] Core of selftest framework (v6) David Malcolm
@ 2016-06-02 23:21                                   ` Bernd Schmidt
  2016-06-03 18:47                                     ` [PATCH] Selftest framework (v7) David Malcolm
  0 siblings, 1 reply; 176+ messages in thread
From: Bernd Schmidt @ 2016-06-02 23:21 UTC (permalink / raw)
  To: David Malcolm, gcc-patches; +Cc: Jeff Law

On 06/02/2016 11:06 PM, David Malcolm wrote:
> gcc/ChangeLog:
> 	* Makefile.in (OBJS): Add function-tests.o,
> 	hash-map-tests.o, hash-set-tests.o, rtl-tests.o,
> 	selftest-run-tests.o.
> 	(OBJS-libcommon): Add selftest.o.
> 	(OBJS-libcommon-target): Add selftest.o.
> 	(all.internal): Add "selftests".
> 	(all.cross): Likewise.
> 	(selftests): New phony target.
> 	(s-selftests): New target.
> 	(selftests-gdb): New phony target.
> 	(COLLECT2_OBJS): Add selftest.o.
> 	* common.opt (fself-test): New.
> 	* selftest-run-tests.c: New file.
> 	* selftest.c: New file.
> 	* selftest.h: New file.
> 	* toplev.c: Include selftest.h.
> 	(toplev::run_self_tests): New.
> 	(toplev::main): Handle -fself-test.
> 	* toplev.h (toplev::run_self_tests): New.

This one looks good to me. I kind of liked the auto-registration, but I 
guess manually calling functions is preferrable to including C files and 
similar in effort required. So it's probably better this way.

> +  fprintf (stderr,
> +	   "%s:%i: FAIL: %s\n",
> +	   file, line, msg);
> +  /* TODO: add calling function name as well?  */
> +  abort ();
> +}

That'll fit on one line. Otherwise OK. Likewise for anything Jeff has 
already approved in a different form - but please make another pass and 
add brief function comments for new functions, and please ensure every 
step you commit actually compiles (this patch alone won't). Let me know 
which patches still need approval after that.


Bernd

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [PATCH] Selftest framework (v7)
  2016-06-02 23:21                                   ` Bernd Schmidt
@ 2016-06-03 18:47                                     ` David Malcolm
  2016-06-05 11:38                                       ` Bernd Schmidt
  0 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2016-06-03 18:47 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, Jeff Law, David Malcolm

On Fri, 2016-06-03 at 01:21 +0200, Bernd Schmidt wrote:
> On 06/02/2016 11:06 PM, David Malcolm wrote:
> > gcc/ChangeLog:
> > 	* Makefile.in (OBJS): Add function-tests.o,
> > 	hash-map-tests.o, hash-set-tests.o, rtl-tests.o,
> > 	selftest-run-tests.o.
> > 	(OBJS-libcommon): Add selftest.o.
> > 	(OBJS-libcommon-target): Add selftest.o.
> > 	(all.internal): Add "selftests".
> > 	(all.cross): Likewise.
> > 	(selftests): New phony target.
> > 	(s-selftests): New target.
> > 	(selftests-gdb): New phony target.
> > 	(COLLECT2_OBJS): Add selftest.o.
> > 	* common.opt (fself-test): New.
> > 	* selftest-run-tests.c: New file.
> > 	* selftest.c: New file.
> > 	* selftest.h: New file.
> > 	* toplev.c: Include selftest.h.
> > 	(toplev::run_self_tests): New.
> > 	(toplev::main): Handle -fself-test.
> > 	* toplev.h (toplev::run_self_tests): New.
>
> This one looks good to me. I kind of liked the auto-registration, but
> I
> guess manually calling functions is preferrable to including C files
> and
> similar in effort required. So it's probably better this way.

Thanks.

> > +  fprintf (stderr,
> > +	   "%s:%i: FAIL: %s\n",
> > +	   file, line, msg);
> > +  /* TODO: add calling function name as well?  */
> > +  abort ();
> > +}
>
> That'll fit on one line.

Fixed.

> Otherwise OK. Likewise for anything Jeff has
> already approved in a different form - but please make another pass
> and
> add brief function comments for new functions,

Done.

> and please ensure every
> step you commit actually compiles (this patch alone won't).

Given that this would all be committed atomically, here's a merged
version of the patch.

I've also rebased the code against today's trunk (r237076).

> Let me know which patches still need approval after that.

I believe I can self-approve the changes to diagnostic-show-locus.c

You've approved the new selftests.* files (I fixed the linewrap issue
you identified) and the changes to Makefile.in, common.opt, and toplev.c.

Remaining approvals needed:

The spellcheck.c changes (moving from a plugin) still need approval.

Jeff approved older versions of the rest of this patch with this
message:
> OK if/when prereqs are approved.  Minor twiddling if we end up moving it
> elsewhere or standardizing/reducing header files is pre-approved.

Since those reviews, the tests have been moved around,
gained comments, and various tweaking.

I've also ported them to the new API.

It's not clear to me if these approvals still hold.  In particular,
the wide-int.cc tests required a substantial rewrite; otherwise
the tweaking could reasonably be described as "minor".

Specifically, Jeff's reviews were:

  bitmap.c changes (as unittests/test-bitmap.c):
    https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03284.html

  et-forest.c additions:
    https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03295.html

  fold-const.c additions (as unittests/test-folding.c):
    https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03305.html

  function-tests.c (as unittests/test-functions.c):
    https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03310.html

  gimple.c additions (as unittests/test-gimple.c):
    https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03304.html

  hash-map-tests.c (as unittests/test-hash-map.c):
    https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03301.html

  hash-set-tests.c (as unittests/test-hash-set.c):
    https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03300.html

  input.c additions (as unittests/test-locations.c):
    https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03307.html

  rtl-tests.c (as unittests/test-rtl.c):
    https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03302.html

  tree.c additions (as unittests/test-tree.c):
    https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03303.html

  tree-cfg.c: add selftests
    https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03285.html
    > Unless there's a good reason, drop the presumably redundant tests
    > and this is OK. Save preapprovald for these changes as the bitmap
    > patch.
    This version does remove the redundant tests.

  vec.c: add selftests (as unittests/test-vec.c):
    https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03308.html

  wide-int.cc: add selftests:
    https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03309.html

   The wide-int.cc tests required a substantial rewrite, since
   they are type-parametrized.

I believe the only changes since my last round of testing have
been:
* the tweaks mentioned above
* rebasing from r236397 (May 18th) to r237076 (today)
* the addition of comments
* squashing it into one patch

I'm re-testing now to be sure (checked and release builds,
bootstrap & regrtest, multi-config build for all in config-list.mk).

Assuming the testing is OK, is this OK for trunk?

gcc/ChangeLog:
	* Makefile.in (OBJS): Add function-tests.o,
	hash-map-tests.o, hash-set-tests.o, rtl-tests.o,
	selftest-run-tests.o.
	(OBJS-libcommon): Add selftest.o.
	(OBJS-libcommon-target): Add selftest.o.
	(all.internal): Add "selftests".
	(all.cross): Likewise.
	(selftests): New phony target.
	(s-selftests): New target.
	(selftests-gdb): New phony target.
	(COLLECT2_OBJS): Add selftest.o.
	* bitmap.c: Include "selftest.h".
	(test_gc_alloc): New function.
	(test_set_range): New function.
	(test_clear_bit_in_middle): New function.
	(test_copying): New function.
	(test_bitmap_single_bit_set_p): New function.
	(selftest::bitmap_c_tests): New function.
	* common.opt (fself-test): New.
	* diagnostic-show-locus.c: Include "selftest.h".
	(make_range): New function.
	(test_range_contains_point_for_single_point): New function.
	(test_range_contains_point_test_for_single_line): New function.
	(test_range_contains_point_for_multiple_lines): New function.
	(assert_eq): New function.
	(test_get_line_width_without_trailing_whitespace): New function.
	(selftest::diagnostic_show_locus_c_tests): New function.
	* et-forest.c: Include "selftest.h".
	(test_single_node): New function.
	(test_simple_tree): New function.
	(test_disconnected_nodes): New function.
	(selftest::et_forest_c_tests): New function.
	* fold-const.c: Include "selftest.h".
	(assert_binop_folds_to_const): New function.
	(assert_binop_folds_to_nonlvalue): New function.
	(test_arithmetic_folding): New function.
	(selftest::fold_const_c_tests): New function.
	* function-tests.c: New file.
	* gimple.c: Include "selftest.h".
	Include "gimple-pretty-print.h".
	(verify_gimple_pp): New function.
	(test_assign_single): New function.
	(test_assign_binop): New function.
	(test_nop_stmt): New function.
	(test_return_stmt): New function.
	(test_return_without_value): New function.
	(selftest::gimple_c_tests): New function.
	* hash-map-tests.c: New file.
	* hash-set-tests.c: New file.
	* input.c: Include "selftest.h".
	(assert_loceq): New function.
	(test_accessing_ordinary_linemaps): New function.
	(test_unknown_location): New function.
	(test_builtins): New function.
	(test_reading_source_line): New function.
	(selftest::input_c_tests): New function.
	* rtl-tests.c: New file.
	* selftest-run-tests.c: New file.
	* selftest.c: New file.
	* selftest.h: New file.
	* spellcheck.c: Include "selftest.h".
	(levenshtein_distance_unit_test_oneway): New function, adapted
	from testsuite/gcc.dg/plugin/levenshtein_plugin.c.
	(levenshtein_distance_unit_test): Likewise.
	(selftest::spellcheck_c_tests): Likewise.
	* toplev.c: Include selftest.h.
	(toplev::run_self_tests): New.
	(toplev::main): Handle -fself-test.
	* toplev.h (toplev::run_self_tests): New.
	* tree.c: Include "selftest.h".
	(test_integer_constants): New function.
	(test_identifiers): New function.
	(test_labels): New function.
	(selftest::tree_c_tests): New function.
	* tree-cfg.c: Include "selftest.h".
	(push_fndecl): New function.
	(test_linear_chain): New function.
	(test_diamond): New function.
	(test_fully_connected): New function.
	(selftest::tree_cfg_c_tests): New function.
	* vec.c: Include "selftest.h".
	(safe_push_range): New function.
	(test_quick_push): New function.
	(test_safe_push): New function.
	(test_truncate): New function.
	(test_safe_grow_cleared): New function.
	(test_pop): New function.
	(test_safe_insert): New function.
	(test_ordered_remove): New function.
	(test_unordered_remove): New function.
	(test_block_remove): New function.
	(reverse_cmp): New function.
	(test_qsort): New function.
	(selftest::vec_c_tests): New function.c.
	* wide-int.cc: Include selftest.h and wide-int-print.h.
	(from_int <wide_int>): New function.
	(from_int <offset_int>): New function.
	(from_int <widest_int>): New function.
	(assert_deceq): New function.
	(assert_hexeq): New function.
	(test_printing <VALUE_TYPE>): New function template.
	(test_ops <VALUE_TYPE>): New function template.
	(test_comparisons <VALUE_TYPE>): New function template.
	(run_all_wide_int_tests <VALUE_TYPE>): New function template.
	(selftest::wide_int_cc_tests): New function.

gcc/testsuite/ChangeLog:
	* gcc.dg/plugin/levenshtein-test-1.c: Delete.
	* gcc.dg/plugin/levenshtein_plugin.c: Delete.
	* gcc.dg/plugin/plugin.exp (plugin_test_list): Remove the
	above.
---
 gcc/Makefile.in                                  |  31 +-
 gcc/bitmap.c                                     | 113 ++++
 gcc/common.opt                                   |   4 +
 gcc/diagnostic-show-locus.c                      | 167 ++++++
 gcc/et-forest.c                                  | 118 ++++
 gcc/fold-const.c                                 |  80 +++
 gcc/function-tests.c                             | 658 +++++++++++++++++++++++
 gcc/gimple.c                                     | 137 +++++
 gcc/hash-map-tests.c                             |  93 ++++
 gcc/hash-set-tests.c                             |  69 +++
 gcc/input.c                                      | 118 ++++
 gcc/rtl-tests.c                                  | 117 ++++
 gcc/selftest-run-tests.c                         |  77 +++
 gcc/selftest.c                                   |  47 ++
 gcc/selftest.h                                   | 153 ++++++
 gcc/spellcheck.c                                 |  58 ++
 gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c |   9 -
 gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c |  64 ---
 gcc/testsuite/gcc.dg/plugin/plugin.exp           |   1 -
 gcc/toplev.c                                     |  26 +
 gcc/toplev.h                                     |   2 +
 gcc/tree-cfg.c                                   | 279 ++++++++++
 gcc/tree.c                                       |  62 +++
 gcc/vec.c                                        | 192 +++++++
 gcc/wide-int.cc                                  | 170 ++++++
 25 files changed, 2766 insertions(+), 79 deletions(-)
 create mode 100644 gcc/function-tests.c
 create mode 100644 gcc/hash-map-tests.c
 create mode 100644 gcc/hash-set-tests.c
 create mode 100644 gcc/rtl-tests.c
 create mode 100644 gcc/selftest-run-tests.c
 create mode 100644 gcc/selftest.c
 create mode 100644 gcc/selftest.h
 delete mode 100644 gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c
 delete mode 100644 gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 2d6f1e8..78a268f 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1264,6 +1264,7 @@ OBJS = \
 	fold-const.o \
 	fold-const-call.o \
 	function.o \
+	function-tests.o \
 	fwprop.o \
 	gcc-rich-location.o \
 	gcse.o \
@@ -1299,6 +1300,8 @@ OBJS = \
 	graphite-sese-to-poly.o \
 	gtype-desc.o \
 	haifa-sched.o \
+	hash-map-tests.o \
+	hash-set-tests.o \
 	hsa.o \
 	hsa-gen.o \
 	hsa-regalloc.o \
@@ -1399,6 +1402,7 @@ OBJS = \
 	resource.o \
 	rtl-chkp.o \
 	rtl-error.o \
+	rtl-tests.o \
 	rtl.o \
 	rtlhash.o \
 	rtlanal.o \
@@ -1411,6 +1415,7 @@ OBJS = \
 	sel-sched-ir.o \
 	sel-sched-dump.o \
 	sel-sched.o \
+	selftest-run-tests.o \
 	sese.o \
 	shrink-wrap.o \
 	simplify-rtx.o \
@@ -1543,13 +1548,14 @@ OBJS = \
 # no target dependencies.
 OBJS-libcommon = diagnostic.o diagnostic-color.o diagnostic-show-locus.o \
 	pretty-print.o intl.o \
-	vec.o input.o version.o hash-table.o ggc-none.o memory-block.o
+	vec.o input.o version.o hash-table.o ggc-none.o memory-block.o \
+	selftest.o
 
 # Objects in libcommon-target.a, used by drivers and by the core
 # compiler and containing target-dependent code.
 OBJS-libcommon-target = $(common_out_object_file) prefix.o params.o \
 	opts.o opts-common.o options.o vec.o hooks.o common/common-targhooks.o \
-	hash-table.o file-find.o spellcheck.o
+	hash-table.o file-find.o spellcheck.o selftest.o
 
 # This lists all host objects for the front ends.
 ALL_HOST_FRONTEND_OBJS = $(foreach v,$(CONFIG_LANGUAGES),$($(v)_OBJS))
@@ -1816,10 +1822,10 @@ config.status: $(srcdir)/configure $(srcdir)/config.gcc
 quickstrap: all
 	cd $(toplevel_builddir) && $(MAKE) all-target-libgcc
 
-all.internal: start.encap rest.encap doc
+all.internal: start.encap rest.encap doc selftests
 # This is what to compile if making a cross-compiler.
 all.cross: native gcc-cross$(exeext) cpp$(exeext) specs \
-	libgcc-support lang.all.cross doc @GENINSRC@ srcextra
+	libgcc-support lang.all.cross doc selftests @GENINSRC@ srcextra
 # This is what must be made before installing GCC and converting libraries.
 start.encap: native xgcc$(exeext) cpp$(exeext) specs \
 	libgcc-support lang.start.encap @GENINSRC@ srcextra
@@ -1839,6 +1845,21 @@ endif
 # This does the things that can't be done on the host machine.
 rest.cross: specs
 
+# Run the selftests during the build once we have a driver and a cc1,
+# so that self-test failures are caught as early as possible.
+# Use "s-selftests" to ensure that we only run the selftests if the
+# driver or cc1 change.
+.PHONY: selftests
+selftests: s-selftests
+s-selftests: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs
+	$(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test
+	$(STAMP) $@
+
+# Convenience method for running selftests under gdb:
+.PHONY: selftests-gdb
+selftests-gdb: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs
+	$(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test -wrapper gdb,--args
+
 # Recompile all the language-independent object files.
 # This is used only if the user explicitly asks for it.
 compilations: $(BACKEND)
@@ -1986,7 +2007,7 @@ gcc-nm.c: gcc-ar.c
 	cp $^ $@
 
 COLLECT2_OBJS = collect2.o collect2-aix.o tlink.o vec.o ggc-none.o \
-  collect-utils.o file-find.o hash-table.o
+  collect-utils.o file-find.o hash-table.o selftest.o
 COLLECT2_LIBS = @COLLECT2_LIBS@
 collect2$(exeext): $(COLLECT2_OBJS) $(LIBDEPS)
 # Don't try modifying collect2 (aka ld) in place--it might be linking this.
diff --git a/gcc/bitmap.c b/gcc/bitmap.c
index 010cf75..7efd036 100644
--- a/gcc/bitmap.c
+++ b/gcc/bitmap.c
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "bitmap.h"
+#include "selftest.h"
 
 /* Memory allocation statistics purpose instance.  */
 mem_alloc_description<bitmap_usage> bitmap_mem_desc;
@@ -2162,5 +2163,117 @@ debug (const bitmap_head *ptr)
     fprintf (stderr, "<nil>\n");
 }
 
+#if CHECKING_P
+
+/* Selftests for bitmaps.  */
+
+/* Freshly-created bitmaps ought to be empty.  */
+
+static void
+test_gc_alloc ()
+{
+  bitmap b = bitmap_gc_alloc ();
+  ASSERT_TRUE (bitmap_empty_p (b));
+}
+
+/* Verify bitmap_set_range.  */
+
+static void
+test_set_range ()
+{
+  bitmap b = bitmap_gc_alloc ();
+  ASSERT_TRUE (bitmap_empty_p (b));
+
+  bitmap_set_range (b, 7, 5);
+  ASSERT_FALSE (bitmap_empty_p (b));
+  ASSERT_EQ (5, bitmap_count_bits (b));
+
+  /* Verify bitmap_bit_p at the boundaries.  */
+  ASSERT_FALSE (bitmap_bit_p (b, 6));
+  ASSERT_TRUE (bitmap_bit_p (b, 7));
+  ASSERT_TRUE (bitmap_bit_p (b, 11));
+  ASSERT_FALSE (bitmap_bit_p (b, 12));
+}
+
+/* Verify splitting a range into two pieces using bitmap_clear_bit.  */
+
+static void
+test_clear_bit_in_middle ()
+{
+  bitmap b = bitmap_gc_alloc ();
+
+  /* Set b to [100..200].  */
+  bitmap_set_range (b, 100, 100);
+  ASSERT_EQ (100, bitmap_count_bits (b));
+
+  /* Clear a bit in the middle.  */
+  bool changed = bitmap_clear_bit (b, 150);
+  ASSERT_TRUE (changed);
+  ASSERT_EQ (99, bitmap_count_bits (b));
+  ASSERT_TRUE (bitmap_bit_p (b, 149));
+  ASSERT_FALSE (bitmap_bit_p (b, 150));
+  ASSERT_TRUE (bitmap_bit_p (b, 151));
+}
+
+/* Verify bitmap_copy.  */
+
+static void
+test_copying ()
+{
+  bitmap src = bitmap_gc_alloc ();
+  bitmap_set_range (src, 40, 10);
+
+  bitmap dst = bitmap_gc_alloc ();
+  ASSERT_FALSE (bitmap_equal_p (src, dst));
+  bitmap_copy (dst, src);
+  ASSERT_TRUE (bitmap_equal_p (src, dst));
+
+  /* Verify that we can make them unequal again...  */
+  bitmap_set_range (src, 70, 5);
+  ASSERT_FALSE (bitmap_equal_p (src, dst));
+
+  /* ...and that changing src after the copy didn't affect
+     the other: */
+  ASSERT_FALSE (bitmap_bit_p (dst, 70));
+}
+
+/* Verify bitmap_single_bit_set_p.  */
+
+static void
+test_bitmap_single_bit_set_p ()
+{
+  bitmap b = bitmap_gc_alloc ();
+
+  ASSERT_FALSE (bitmap_single_bit_set_p (b));
+
+  bitmap_set_range (b, 42, 1);
+  ASSERT_TRUE (bitmap_single_bit_set_p (b));
+  ASSERT_EQ (42, bitmap_first_set_bit (b));
+
+  bitmap_set_range (b, 1066, 1);
+  ASSERT_FALSE (bitmap_single_bit_set_p (b));
+  ASSERT_EQ (42, bitmap_first_set_bit (b));
+
+  bitmap_clear_range (b, 0, 100);
+  ASSERT_TRUE (bitmap_single_bit_set_p (b));
+  ASSERT_EQ (1066, bitmap_first_set_bit (b));
+}
+
+namespace selftest {
+
+/* Run all of the selftests within this file.  */
+
+void
+bitmap_c_tests ()
+{
+  test_gc_alloc ();
+  test_set_range ();
+  test_clear_bit_in_middle ();
+  test_copying ();
+  test_bitmap_single_bit_set_p ();
+}
+
+} // namespace selftest
+#endif /* CHECKING_P */
 
 #include "gt-bitmap.h"
diff --git a/gcc/common.opt b/gcc/common.opt
index 2bb576c..632dd31 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2066,6 +2066,10 @@ fselective-scheduling2
 Common Report Var(flag_selective_scheduling2) Optimization
 Run selective scheduling after reload.
 
+fself-test
+Common Undocumented Var(flag_self_test)
+Run self-tests.
+
 fsel-sched-pipelining
 Common Report Var(flag_sel_sched_pipelining) Init(0) Optimization
 Perform software pipelining of inner loops during selective scheduling.
diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
index eeccee5..0142e1f 100644
--- a/gcc/diagnostic-show-locus.c
+++ b/gcc/diagnostic-show-locus.c
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "backtrace.h"
 #include "diagnostic.h"
 #include "diagnostic-color.h"
+#include "selftest.h"
 
 #ifdef HAVE_TERMIOS_H
 # include <termios.h>
@@ -442,6 +443,124 @@ layout_range::contains_point (int row, int column) const
   return column <= m_finish.m_column;
 }
 
+#if CHECKING_P
+
+/* A helper function for testing layout_range::contains_point.  */
+
+static layout_range
+make_range (int start_line, int start_col,
+	    int end_line, int end_col)
+{
+  const expanded_location start_exploc
+    = {"test.c", start_line, start_col, NULL, false};
+  const expanded_location finish_exploc
+    = {"test.c", end_line, end_col, NULL, false};
+  return layout_range (&start_exploc, &finish_exploc, false,
+		       &start_exploc);
+}
+
+/* Selftests for layout_range::contains_point.  */
+
+/* Selftest for layout_range::contains_point where the layout_range
+   is a range with start==end i.e. a single point.  */
+
+static void
+test_range_contains_point_for_single_point ()
+{
+  layout_range point = make_range (7, 10, 7, 10);
+
+  /* Before the line. */
+  ASSERT_FALSE (point.contains_point (6, 1));
+
+  /* On the line, but before start.  */
+  ASSERT_FALSE (point.contains_point (7, 9));
+
+  /* At the point.  */
+  ASSERT_TRUE (point.contains_point (7, 10));
+
+  /* On the line, after the point.  */
+  ASSERT_FALSE (point.contains_point (7, 11));
+
+  /* After the line.  */
+  ASSERT_FALSE (point.contains_point (8, 1));
+}
+
+/* Selftest for layout_range::contains_point where the layout_range
+   is the single-line range shown as "Example A" above.  */
+
+static void
+test_range_contains_point_test_for_single_line ()
+{
+  layout_range example_a = make_range (2, 22, 2, 38);
+
+  /* Before the line. */
+  ASSERT_FALSE (example_a.contains_point (1, 1));
+
+  /* On the line, but before start.  */
+  ASSERT_FALSE (example_a.contains_point (2, 21));
+
+  /* On the line, at the start.  */
+  ASSERT_TRUE (example_a.contains_point (2, 22));
+
+  /* On the line, within the range.  */
+  ASSERT_TRUE (example_a.contains_point (2, 23));
+
+  /* On the line, at the end.  */
+  ASSERT_TRUE (example_a.contains_point (2, 38));
+
+  /* On the line, after the end.  */
+  ASSERT_FALSE (example_a.contains_point (2, 39));
+
+  /* After the line.  */
+  ASSERT_FALSE (example_a.contains_point (2, 39));
+}
+
+/* Selftest for layout_range::contains_point where the layout_range
+   is the multi-line range shown as "Example B" above.  */
+
+static void
+test_range_contains_point_for_multiple_lines ()
+{
+  layout_range example_b = make_range (3, 14, 5, 8);
+
+  /* Before first line. */
+  ASSERT_FALSE (example_b.contains_point (1, 1));
+
+  /* On the first line, but before start.  */
+  ASSERT_FALSE (example_b.contains_point (3, 13));
+
+  /* At the start.  */
+  ASSERT_TRUE (example_b.contains_point (3, 14));
+
+  /* On the first line, within the range.  */
+  ASSERT_TRUE (example_b.contains_point (3, 15));
+
+  /* On an interior line.
+     The column number should not matter; try various boundary
+     values.  */
+  ASSERT_TRUE (example_b.contains_point (4, 1));
+  ASSERT_TRUE (example_b.contains_point (4, 7));
+  ASSERT_TRUE (example_b.contains_point (4, 8));
+  ASSERT_TRUE (example_b.contains_point (4, 9));
+  ASSERT_TRUE (example_b.contains_point (4, 13));
+  ASSERT_TRUE (example_b.contains_point (4, 14));
+  ASSERT_TRUE (example_b.contains_point (4, 15));
+
+  /* On the final line, before the end.  */
+  ASSERT_TRUE (example_b.contains_point (5, 7));
+
+  /* On the final line, at the end.  */
+  ASSERT_TRUE (example_b.contains_point (5, 8));
+
+  /* On the final line, after the end.  */
+  ASSERT_FALSE (example_b.contains_point (5, 9));
+
+  /* After the line.  */
+  ASSERT_FALSE (example_b.contains_point (6, 1));
+}
+
+#endif /* #if CHECKING_P */
+
 /* Given a source line LINE of length LINE_WIDTH, determine the width
    without any trailing whitespace.  */
 
@@ -465,6 +584,34 @@ get_line_width_without_trailing_whitespace (const char *line, int line_width)
   return result;
 }
 
+#if CHECKING_P
+
+/* A helper function for testing get_line_width_without_trailing_whitespace.  */
+
+static void
+assert_eq (const char *line, int expected_width)
+{
+  int actual_value
+    = get_line_width_without_trailing_whitespace (line, strlen (line));
+  ASSERT_EQ (actual_value, expected_width);
+}
+
+/* Verify that get_line_width_without_trailing_whitespace is sane for
+   various inputs.  It is not required to handle newlines.  */
+
+static void
+test_get_line_width_without_trailing_whitespace ()
+{
+  assert_eq ("", 0);
+  assert_eq (" ", 0);
+  assert_eq ("\t", 0);
+  assert_eq ("hello world", 11);
+  assert_eq ("hello world     ", 11);
+  assert_eq ("hello world     \t\t  ", 11);
+}
+
+#endif /* #if CHECKING_P */
+
 /* Helper function for layout's ctor, for sanitizing locations relative
    to the primary location within a diagnostic.
 
@@ -1171,3 +1318,23 @@ diagnostic_show_locus (diagnostic_context * context,
 
   pp_set_prefix (context->printer, saved_prefix);
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Run all of the selftests within this file.  */
+
+void
+diagnostic_show_locus_c_tests ()
+{
+  test_range_contains_point_for_single_point ();
+  test_range_contains_point_test_for_single_line ();
+  test_range_contains_point_for_multiple_lines ();
+
+  test_get_line_width_without_trailing_whitespace ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/et-forest.c b/gcc/et-forest.c
index cd36752..67dbf35 100644
--- a/gcc/et-forest.c
+++ b/gcc/et-forest.c
@@ -27,6 +27,7 @@ License along with libiberty; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "alloc-pool.h"
 #include "et-forest.h"
+#include "selftest.h"
 
 /* We do not enable this with CHECKING_P, since it is awfully slow.  */
 #undef DEBUG_ET
@@ -764,3 +765,120 @@ et_root (struct et_node *node)
 
   return r->of;
 }
+
+#if CHECKING_P
+
+/* Selftests for et-forest.c.  */
+
+/* Perform sanity checks for a tree consisting of a single node.  */
+
+static void
+test_single_node ()
+{
+  void *test_data = (void *)0xcafebabe;
+
+  et_node *n = et_new_tree (test_data);
+  ASSERT_EQ (n->data, test_data);
+  ASSERT_EQ (n, et_root (n));
+  et_free_tree (n);
+}
+
+/* Test of this tree:
+       a
+      / \
+     /   \
+    b     c
+   / \    |
+  d   e   f.  */
+
+static void
+test_simple_tree ()
+{
+  et_node *a = et_new_tree (NULL);
+  et_node *b = et_new_tree (NULL);
+  et_node *c = et_new_tree (NULL);
+  et_node *d = et_new_tree (NULL);
+  et_node *e = et_new_tree (NULL);
+  et_node *f = et_new_tree (NULL);
+
+  et_set_father (b, a);
+  et_set_father (c, a);
+  et_set_father (d, b);
+  et_set_father (e, b);
+  et_set_father (f, c);
+
+  ASSERT_TRUE (et_below (a, a));
+  ASSERT_TRUE (et_below (b, a));
+  ASSERT_TRUE (et_below (c, a));
+  ASSERT_TRUE (et_below (d, a));
+  ASSERT_TRUE (et_below (e, a));
+  ASSERT_TRUE (et_below (f, a));
+
+  ASSERT_FALSE (et_below (a, b));
+  ASSERT_TRUE (et_below (b, b));
+  ASSERT_FALSE (et_below (c, b));
+  ASSERT_TRUE (et_below (d, b));
+  ASSERT_TRUE (et_below (e, b));
+  ASSERT_FALSE (et_below (f, b));
+
+  ASSERT_FALSE (et_below (a, c));
+  ASSERT_FALSE (et_below (b, c));
+  ASSERT_TRUE (et_below (c, c));
+  ASSERT_FALSE (et_below (d, c));
+  ASSERT_FALSE (et_below (e, c));
+  ASSERT_TRUE (et_below (f, c));
+
+  ASSERT_FALSE (et_below (a, d));
+  ASSERT_FALSE (et_below (b, d));
+  ASSERT_FALSE (et_below (c, d));
+  ASSERT_TRUE (et_below (d, d));
+  ASSERT_FALSE (et_below (e, d));
+  ASSERT_FALSE (et_below (f, d));
+
+  ASSERT_FALSE (et_below (a, e));
+  ASSERT_FALSE (et_below (b, e));
+  ASSERT_FALSE (et_below (c, e));
+  ASSERT_FALSE (et_below (d, e));
+  ASSERT_TRUE (et_below (e, e));
+  ASSERT_FALSE (et_below (f, e));
+
+  ASSERT_FALSE (et_below (a, f));
+  ASSERT_FALSE (et_below (b, f));
+  ASSERT_FALSE (et_below (c, f));
+  ASSERT_FALSE (et_below (d, f));
+  ASSERT_FALSE (et_below (e, f));
+  ASSERT_TRUE (et_below (f, f));
+
+  et_free_tree_force (a);
+}
+
+/* Verify that two disconnected nodes are unrelated.  */
+
+static void
+test_disconnected_nodes ()
+{
+  et_node *a = et_new_tree (NULL);
+  et_node *b = et_new_tree (NULL);
+
+  ASSERT_FALSE (et_below (a, b));
+  ASSERT_FALSE (et_below (b, a));
+
+  et_free_tree (a);
+  et_free_tree (b);
+}
+
+namespace selftest {
+
+/* Run all of the selftests within this file.  */
+
+void
+et_forest_c_tests ()
+{
+  test_single_node ();
+  test_simple_tree ();
+  test_disconnected_nodes ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 5058746..25af7ed 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -76,6 +76,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "case-cfn-macros.h"
 #include "stringpool.h"
 #include "tree-ssanames.h"
+#include "selftest.h"
 
 #ifndef LOAD_EXTEND_OP
 #define LOAD_EXTEND_OP(M) UNKNOWN
@@ -14496,3 +14497,82 @@ c_getstr (tree src)
 
   return TREE_STRING_POINTER (src) + tree_to_uhwi (offset_node);
 }
+
+#if CHECKING_P
+
+/* Helper functions for writing tests of folding trees.  */
+
+/* Verify that the binary op (LHS CODE RHS) folds to CONSTANT.  */
+
+static void
+assert_binop_folds_to_const (tree lhs, enum tree_code code, tree rhs,
+			     tree constant)
+{
+  ASSERT_EQ (constant, fold_build2 (code, TREE_TYPE (lhs), lhs, rhs));
+}
+
+/* Verify that the binary op (LHS CODE RHS) folds to an NON_LVALUE_EXPR
+   wrapping WRAPPED_EXPR.  */
+
+static void
+assert_binop_folds_to_nonlvalue (tree lhs, enum tree_code code, tree rhs,
+				 tree wrapped_expr)
+{
+  tree result = fold_build2 (code, TREE_TYPE (lhs), lhs, rhs);
+  ASSERT_NE (wrapped_expr, result);
+  ASSERT_EQ (NON_LVALUE_EXPR, TREE_CODE (result));
+  ASSERT_EQ (wrapped_expr, TREE_OPERAND (result, 0));
+}
+
+/* Verify that various arithmetic binary operations are folded
+   correctly.  */
+
+static void
+test_arithmetic_folding ()
+{
+  tree type = integer_type_node;
+  tree x = create_tmp_var_raw (type, "x");
+  tree zero = build_zero_cst (type);
+  tree one = build_int_cst (type, 1);
+
+  /* Addition.  */
+  /* 1 <-- (0 + 1) */
+  assert_binop_folds_to_const (zero, PLUS_EXPR, one,
+			       one);
+  assert_binop_folds_to_const (one, PLUS_EXPR, zero,
+			       one);
+
+  /* (nonlvalue)x <-- (x + 0) */
+  assert_binop_folds_to_nonlvalue (x, PLUS_EXPR, zero,
+				   x);
+
+  /* Subtraction.  */
+  /* 0 <-- (x - x) */
+  assert_binop_folds_to_const (x, MINUS_EXPR, x,
+			       zero);
+  assert_binop_folds_to_nonlvalue (x, MINUS_EXPR, zero,
+				   x);
+
+  /* Multiplication.  */
+  /* 0 <-- (x * 0) */
+  assert_binop_folds_to_const (x, MULT_EXPR, zero,
+			       zero);
+
+  /* (nonlvalue)x <-- (x * 1) */
+  assert_binop_folds_to_nonlvalue (x, MULT_EXPR, one,
+				   x);
+}
+
+namespace selftest {
+
+/* Run all of the selftests within this file.  */
+
+void
+fold_const_c_tests ()
+{
+  test_arithmetic_folding ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
diff --git a/gcc/function-tests.c b/gcc/function-tests.c
new file mode 100644
index 0000000..e8bfb5c
--- /dev/null
+++ b/gcc/function-tests.c
@@ -0,0 +1,658 @@
+/* Unit tests for function-handling.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "hard-reg-set.h"
+#include "input.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "gimple-expr.h"
+#include "toplev.h"
+#include "print-tree.h"
+#include "tree-iterator.h"
+#include "gimplify.h"
+#include "tree-cfg.h"
+#include "basic-block.h"
+#include "double-int.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "stmt.h"
+#include "hash-table.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "context.h"
+#include "hash-map.h"
+#include "plugin-api.h"
+#include "ipa-ref.h"
+#include "cgraph.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+/* Helper function for selftests of function-creation.  */
+
+static tree
+make_fndecl (tree return_type,
+	     const char *name,
+	     vec <tree> &param_types,
+	     bool is_variadic = false)
+{
+  tree fn_type;
+  if (is_variadic)
+    fn_type = build_varargs_function_type_array (return_type,
+						 param_types.length (),
+						 param_types.address ());
+  else
+    fn_type = build_function_type_array (return_type,
+					 param_types.length (),
+					 param_types.address ());
+  /* FIXME: this uses input_location: */
+  tree fndecl = build_fn_decl (name, fn_type);
+
+  return fndecl;
+}
+
+/* Verify creating a function declaration equivalent to the following
+     int test_fndecl_int_void (void);
+   C declaration.  */
+
+static void
+test_fndecl_int_void ()
+{
+  auto_vec <tree> param_types;
+  const char *name = "test_fndecl_int_void";
+  tree fndecl = make_fndecl (integer_type_node,
+			     name,
+			     param_types);
+  ASSERT_TRUE (fndecl != NULL);
+
+  /* Verify name of decl.  */
+  tree declname = DECL_NAME (fndecl);
+  ASSERT_TRUE (declname != NULL);
+  ASSERT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
+  /* We expect it to use a *copy* of the string we passed in.  */
+  const char *identifier_ptr = IDENTIFIER_POINTER (declname);
+  ASSERT_NE (name, identifier_ptr);
+  ASSERT_EQ (0, strcmp ("test_fndecl_int_void", identifier_ptr));
+
+  /* Verify type of fndecl.  */
+  ASSERT_EQ (FUNCTION_DECL, TREE_CODE (fndecl));
+  tree fntype = TREE_TYPE (fndecl);
+  ASSERT_EQ (FUNCTION_TYPE, TREE_CODE (fntype));
+
+  /* Verify return type.  */
+  ASSERT_EQ (integer_type_node, TREE_TYPE (fntype));
+
+  /* Verify "void" args.  */
+  tree argtypes = TYPE_ARG_TYPES (fntype);
+  ASSERT_EQ (TREE_LIST, TREE_CODE (argtypes));
+  ASSERT_EQ (void_type_node, TREE_VALUE (argtypes));
+  ASSERT_EQ (NULL, TREE_CHAIN (argtypes));
+}
+
+/* Verify creating a function declaration equivalent to the following
+     float test_fndecl_float_intchar (int, char);
+   C declaration.  */
+
+static void
+test_fndecl_float_intchar ()
+{
+  auto_vec <tree> param_types;
+  param_types.safe_push (integer_type_node);
+  param_types.safe_push (char_type_node);
+  const char *name = "test_fndecl_float_intchar";
+  tree fndecl = make_fndecl (float_type_node,
+			     name,
+			     param_types);
+  ASSERT_TRUE (fndecl != NULL);
+
+  /* Verify name of decl.  */
+  tree declname = DECL_NAME (fndecl);
+  ASSERT_TRUE (declname != NULL);
+  ASSERT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
+  /* We expect it to use a *copy* of the string we passed in.  */
+  const char *identifier_ptr = IDENTIFIER_POINTER (declname);
+  ASSERT_NE (name, identifier_ptr);
+  ASSERT_EQ (0, strcmp (name, identifier_ptr));
+
+  /* Verify type of fndecl.  */
+  ASSERT_EQ (FUNCTION_DECL, TREE_CODE (fndecl));
+  tree fntype = TREE_TYPE (fndecl);
+  ASSERT_EQ (FUNCTION_TYPE, TREE_CODE (fntype));
+
+  /* Verify return type.  */
+  ASSERT_EQ (float_type_node, TREE_TYPE (fntype));
+
+  /* Verify "(int, char)" args.  */
+  tree arg0 = TYPE_ARG_TYPES (fntype);
+  ASSERT_EQ (TREE_LIST, TREE_CODE (arg0));
+  ASSERT_EQ (integer_type_node, TREE_VALUE (arg0));
+  tree arg1 = TREE_CHAIN (arg0);
+  ASSERT_TRUE (arg1 != NULL);
+  ASSERT_EQ (TREE_LIST, TREE_CODE (arg1));
+  ASSERT_EQ (char_type_node, TREE_VALUE (arg1));
+  tree argterm = TREE_CHAIN (arg1);
+  ASSERT_TRUE (argterm != NULL);
+  ASSERT_EQ (TREE_LIST, TREE_CODE (argterm));
+  ASSERT_EQ (void_type_node, TREE_VALUE (argterm));
+  ASSERT_EQ (NULL, TREE_CHAIN (argterm));
+}
+
+/* The test cases using these helper functions take a trivial function:
+
+     int test_fn (void) { return 42; }
+
+   and test various conversions done to it:
+
+   - gimplification
+   - construction of the CFG
+   - conversion to SSA form
+   - expansion to RTL form
+
+   In avoid having one overlong test case, this is broken
+   up into separate test cases for each stage, with helper functions
+   to minimize code duplication.
+
+   Another approach would be to attempt to directly construct a function
+   in the appropriate representation at each stage, though presumably
+   that would exhibit different kinds of failure compared to this
+   approach.  */
+
+/* Construct this function:
+   int test_fn (void) { return 42; }
+   in generic tree form.  Return the fndecl.  */
+
+static tree
+build_trivial_generic_function ()
+{
+  auto_vec <tree> param_types;
+  tree fndecl = make_fndecl (integer_type_node,
+			     "test_fn",
+			     param_types);
+  ASSERT_TRUE (fndecl != NULL);
+
+  /* Populate the function.  */
+  tree retval = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+			    NULL_TREE, integer_type_node);
+  DECL_ARTIFICIAL (retval) = 1;
+  DECL_IGNORED_P (retval) = 1;
+  DECL_RESULT (fndecl) = retval;
+
+  /* Create a BIND_EXPR, and within it, a statement list.  */
+  tree stmt_list = alloc_stmt_list ();
+  tree_stmt_iterator stmt_iter = tsi_start (stmt_list);
+  tree block = make_node (BLOCK);
+  tree bind_expr =
+    build3 (BIND_EXPR, void_type_node, NULL, stmt_list, block);
+
+  tree modify_retval = build2 (MODIFY_EXPR,
+			       integer_type_node,
+			       retval,
+			       build_int_cst (integer_type_node, 42));
+  tree return_stmt = build1 (RETURN_EXPR,
+			     integer_type_node,
+			     modify_retval);
+  tsi_link_after (&stmt_iter, return_stmt, TSI_CONTINUE_LINKING);
+
+  DECL_INITIAL (fndecl) = block;
+
+  /* how to add to function? the following appears to be how to
+     set the body of a fndecl: */
+  DECL_SAVED_TREE(fndecl) = bind_expr;
+
+  /* Ensure that locals appear in the debuginfo.  */
+  BLOCK_VARS (block) = BIND_EXPR_VARS (bind_expr);
+
+  return fndecl;
+}
+
+/* Construct this function:
+     int test_fn (void) { return 42; }
+   in "high gimple" form.  Return the fndecl.  */
+
+static tree
+build_trivial_high_gimple_function ()
+{
+  /* Construct a trivial function, and gimplify it: */
+  tree fndecl = build_trivial_generic_function ();
+  gimplify_function_tree (fndecl);
+  return fndecl;
+}
+
+/* Build a CFG for a function in gimple form.  */
+
+static void
+build_cfg (tree fndecl)
+{
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  ASSERT_EQ (fndecl, fun->decl);
+
+  /* We first have to lower control flow; for our trivial test function
+     this gives us:
+	 test_fn ()
+	 {
+	   D.56 = 42;
+	   goto <D.57>;
+	   <D.57>:
+	   return D.56;
+	 }
+  */
+  gimple_opt_pass *lower_cf_pass = make_pass_lower_cf (g);
+  push_cfun (fun);
+  lower_cf_pass->execute (fun);
+  pop_cfun ();
+
+  /* We can now convert to CFG form; for our trivial test function this
+     gives us:
+	 test_fn ()
+	 {
+	   <bb 2>:
+	   D.56 = 42;
+	   return D.56;
+	 }
+  */
+  gimple_opt_pass *build_cfg_pass = make_pass_build_cfg (g);
+  push_cfun (fun);
+  build_cfg_pass->execute (fun);
+  pop_cfun ();
+}
+
+/* Convert a gimple+CFG function to SSA form.  */
+
+static void
+convert_to_ssa (tree fndecl)
+{
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  ASSERT_EQ (fndecl, fun->decl);
+
+  gimple_opt_pass *build_ssa_pass = make_pass_build_ssa (g);
+  push_cfun (fun);
+  build_ssa_pass->execute (fun);
+  pop_cfun ();
+}
+
+/* Assuming we have a simple 3-block CFG like this:
+     [ENTRY] -> [block2] -> [EXIT]
+   get the "real" basic block (block 2).  */
+
+static basic_block
+get_real_block (function *fun)
+{
+  ASSERT_TRUE (fun->cfg != NULL);
+  ASSERT_EQ (3, n_basic_blocks_for_fn (fun));
+  basic_block bb2 = (*fun->cfg->x_basic_block_info)[2];
+  ASSERT_TRUE (bb2 != NULL);
+  return bb2;
+}
+
+/* Verify that we have a simple 3-block CFG: the two "fake" ones, and
+   a "real" one:
+     [ENTRY] -> [block2] -> [EXIT].  */
+
+static void
+verify_three_block_cfg (function *fun)
+{
+  ASSERT_TRUE (fun->cfg != NULL);
+  ASSERT_EQ (3, n_basic_blocks_for_fn (fun));
+  ASSERT_EQ (2, n_edges_for_fn (fun));
+
+  /* The "fake" basic blocks.  */
+  basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (entry != NULL);
+  ASSERT_EQ (ENTRY_BLOCK, entry->index);
+
+  basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (exit != NULL);
+  ASSERT_EQ (EXIT_BLOCK, exit->index);
+
+  /* The "real" basic block.  */
+  basic_block bb2 = get_real_block (fun);
+  ASSERT_TRUE (bb2 != NULL);
+  ASSERT_EQ (2, bb2->index);
+
+  /* Verify connectivity.  */
+  ASSERT_EQ (NULL, entry->preds);
+  ASSERT_EQ (1, entry->succs->length ());
+
+  edge from_entry_to_bb2 = (*entry->succs)[0];
+  ASSERT_EQ (entry, from_entry_to_bb2->src);
+  ASSERT_EQ (bb2, from_entry_to_bb2->dest);
+
+  ASSERT_EQ (1, bb2->preds->length ());
+  ASSERT_EQ (from_entry_to_bb2, (*bb2->preds)[0]);
+  ASSERT_EQ (1, bb2->succs->length ());
+
+  edge from_bb2_to_exit = (*bb2->succs)[0];
+  ASSERT_EQ (bb2, from_bb2_to_exit->src);
+  ASSERT_EQ (exit, from_bb2_to_exit->dest);
+
+  ASSERT_EQ (1, exit->preds->length ());
+  ASSERT_EQ (from_bb2_to_exit, (*exit->preds)[0]);
+  ASSERT_EQ (NULL, exit->succs);
+}
+
+/* As above, but additionally verify the gimple statements are sane.  */
+
+static void
+verify_three_block_gimple_cfg (function *fun)
+{
+  verify_three_block_cfg (fun);
+
+  /* The "fake" basic blocks should be flagged as gimple, but with have no
+     statements.  */
+  basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (entry != NULL);
+  ASSERT_EQ (0, entry->flags & BB_RTL);
+  ASSERT_EQ (NULL, bb_seq (entry));
+
+  basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (exit != NULL);
+  ASSERT_EQ (0, entry->flags & BB_RTL);
+  ASSERT_EQ (NULL, bb_seq (exit));
+
+  /* The "real" basic block should be flagged as gimple, and have one
+     or more statements.  */
+  basic_block bb2 = get_real_block (fun);
+  ASSERT_TRUE (bb2 != NULL);
+  ASSERT_EQ (0, entry->flags & BB_RTL);
+  ASSERT_TRUE (bb_seq (bb2) != NULL);
+}
+
+/* As above, but additionally verify the RTL insns are sane.  */
+
+static void
+verify_three_block_rtl_cfg (function *fun)
+{
+  verify_three_block_cfg (fun);
+
+  /* The "fake" basic blocks should be flagged as RTL, but with no
+     insns.  */
+  basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (entry != NULL);
+  ASSERT_EQ (BB_RTL, entry->flags & BB_RTL);
+  ASSERT_EQ (NULL, BB_HEAD (entry));
+
+  basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (exit != NULL);
+  ASSERT_EQ (BB_RTL, entry->flags & BB_RTL);
+  ASSERT_EQ (NULL, BB_HEAD (exit));
+
+  /* The "real" basic block should be flagged as RTL, and have one
+     or more insns.  */
+  basic_block bb2 = get_real_block (fun);
+  ASSERT_TRUE (bb2 != NULL);
+  ASSERT_EQ (BB_RTL, entry->flags & BB_RTL);
+  ASSERT_TRUE (BB_HEAD (bb2) != NULL);
+}
+
+/* Test converting our trivial function:
+     int test_fn (void) { return 42; }
+   to gimple form.  */
+
+static void
+test_gimplification ()
+{
+  tree fndecl = build_trivial_generic_function ();
+
+  /* Convert to gimple: */
+  gimplify_function_tree (fndecl);
+
+  /* Verify that we got gimple out of it.  */
+
+  /* The function is now in GIMPLE form but the CFG has not been
+     built yet.  */
+
+  /* We should have a struct function for the decl.  */
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  ASSERT_EQ (fndecl, fun->decl);
+
+  /* We expect a GIMPLE_BIND, with two gimple statements within it:
+       tmp = 42;
+       return tmp;  */
+
+  gimple_seq seq_fn_body = gimple_body (fndecl);
+  ASSERT_TRUE (seq_fn_body != NULL);
+  gimple *bind_stmt = gimple_seq_first_stmt (seq_fn_body);
+  ASSERT_EQ (GIMPLE_BIND, gimple_code (bind_stmt));
+  ASSERT_EQ (NULL, bind_stmt->next);
+
+  gimple_seq seq_bind_body = gimple_bind_body (as_a <gbind *> (bind_stmt));
+
+  /* Verify that we have the 2 statements we expect.  */
+  ASSERT_TRUE (seq_bind_body != NULL);
+  gimple *stmt1 = gimple_seq_first_stmt (seq_bind_body);
+  ASSERT_TRUE (stmt1 != NULL);
+  ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt1));
+  gimple *stmt2 = stmt1->next;
+  ASSERT_TRUE (stmt2 != NULL);
+  ASSERT_EQ (stmt1, stmt2->prev);
+  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt2));
+}
+
+/* Test of building a CFG for a function in high gimple form.  */
+
+static void
+test_building_cfg ()
+{
+  /* Construct a trivial function, and gimplify it: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+
+  /* Build a CFG.  */
+  build_cfg (fndecl);
+
+  /* The CFG-building code constructs a 4-block cfg (with
+     ENTRY and EXIT):
+       test_fn ()
+       {
+         <bb 2>:
+	 D.65 = 42;
+
+	 <bb 3>:
+	 return D.65;
+       }
+     and then ought to merge blocks 2 and 3 in cleanup_tree_cfg.
+
+     Hence we should end up with a simple 3-block cfg, the two "fake" ones,
+     and a "real" one:
+       [ENTRY] -> [block2] -> [EXIT]
+     with code like this:
+	 test_fn ()
+	 {
+	   <bb 2>:
+	   D.56 = 42;
+	   return D.56;
+	 }
+  */
+  verify_three_block_gimple_cfg (fun);
+
+  /* Verify the statements within the "real" block.  */
+  basic_block bb2 = get_real_block (fun);
+  gimple *stmt_a = gimple_seq_first_stmt (bb_seq (bb2));
+  ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a));
+  gimple *stmt_b = stmt_a->next;
+  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt_b));
+  ASSERT_EQ (NULL, stmt_b->next);
+}
+
+/* Test of conversion of gimple to SSA form.  */
+
+static void
+test_conversion_to_ssa ()
+{
+  /* As above, construct a trivial function, gimplify it, and build a CFG: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  build_cfg (fndecl);
+
+  convert_to_ssa (fndecl);
+
+  verify_three_block_gimple_cfg (fun);
+
+  /* For out trivial test function we should now have something like
+     this:
+       test_fn ()
+       {
+	 <bb 2>:
+	 _1 = 42;
+	 return _1;
+       }
+  */
+  basic_block bb2 = get_real_block (fun);
+  gimple *stmt_a = gimple_seq_first_stmt (bb_seq (bb2));
+  ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a));
+
+  gimple *stmt_b = stmt_a->next;
+  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt_b));
+  ASSERT_EQ (NULL, stmt_b->next);
+
+  greturn *return_stmt = as_a <greturn *> (stmt_b);
+  ASSERT_EQ (SSA_NAME, TREE_CODE (gimple_return_retval (return_stmt)));
+}
+
+/* Test of expansion from gimple-ssa to RTL.  */
+
+static void
+test_expansion_to_rtl ()
+{
+  /* As above, construct a trivial function, gimplify it, build a CFG,
+     and convert to SSA: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  build_cfg (fndecl);
+  convert_to_ssa (fndecl);
+
+  /* We need a cgraph_node for it.  */
+  cgraph_node::get_create (fndecl);
+  /* Normally, cgraph_node::expand () would call
+     init_function_start (and a bunch of other stuff),
+     and invoke the expand pass, but it also runs
+     all of the other passes.  So just do the minimum
+     needed to get from gimple-SSA to RTL.  */
+  rtl_opt_pass *expand_pass = make_pass_expand (g);
+  push_cfun (fun);
+  init_function_start (fndecl);
+  expand_pass->execute (fun);
+  pop_cfun ();
+
+  /* On x86_64, I get this:
+       (note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+       (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
+       (insn 5 2 6 2 (set (reg:SI 87 [ D.59 ])
+			  (const_int 42 [0x2a])) -1 (nil))
+       (insn 6 5 10 2 (set (reg:SI 88 [ <retval> ])
+			   (reg:SI 87 [ D.59 ])) -1 (nil))
+       (insn 10 6 11 2 (set (reg/i:SI 0 ax)
+			    (reg:SI 88 [ <retval> ])) -1 (nil))
+       (insn 11 10 0 2 (use (reg/i:SI 0 ax)) -1 (nil))
+
+     On cr16-elf I get this:
+       (note 4 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+       (insn 2 4 3 2 (set (reg:SI 24)
+	    (reg/f:SI 16 virtual-incoming-args)) -1
+	  (nil))
+       (note 3 2 6 2 NOTE_INSN_FUNCTION_BEG)
+       (insn 6 3 7 2 (set (reg:HI 22 [ _1 ])
+	    (const_int 42 [0x2a])) -1
+	 (nil))
+       (insn 7 6 11 2 (set (reg:HI 23 [ <retval> ])
+	   (reg:HI 22 [ _1 ])) -1
+	 (nil))
+       (insn 11 7 12 2 (set (reg/i:HI 0 r0)
+	   (reg:HI 23 [ <retval> ])) -1
+	 (nil))
+       (insn 12 11 0 2 (use (reg/i:HI 0 r0)) -1
+	 (nil)).  */
+  verify_three_block_rtl_cfg (fun);
+
+  /* Verify as much of the RTL as we can whilst avoiding
+     target-specific behavior.  */
+  basic_block bb2 = get_real_block (fun);
+
+  /* Expect a NOTE_INSN_BASIC_BLOCK... */
+  rtx_insn *insn = BB_HEAD (bb2);
+  ASSERT_TRUE (insn != NULL);
+  ASSERT_EQ (NOTE, insn->code);
+  ASSERT_EQ (NOTE_INSN_BASIC_BLOCK, NOTE_KIND (insn));
+  ASSERT_EQ (bb2, NOTE_BASIC_BLOCK (insn));
+
+  /* ...etc; any further checks are likely to over-specify things
+     and run us into target dependencies.  */
+}
+
+namespace selftest {
+
+/* Run all of the selftests within this file.  */
+
+void
+function_tests_c_tests ()
+{
+  test_fndecl_int_void ();
+  test_fndecl_float_intchar ();
+  test_gimplification ();
+  test_building_cfg ();
+  test_conversion_to_ssa ();
+  test_expansion_to_rtl ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 226b080..0a15628 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-walk.h"
 #include "gimplify.h"
 #include "target.h"
+#include "selftest.h"
+#include "gimple-pretty-print.h"
 
 
 /* All the tuples have their operand vector (if present) at the very bottom
@@ -3018,3 +3020,138 @@ maybe_remove_unused_call_args (struct function *fn, gimple *stmt)
       update_stmt_fn (fn, stmt);
     }
 }
+
+#if CHECKING_P
+
+/* Selftests for core gimple structures.  */
+
+/* Verify that STMT is pretty-printed as EXPECTED.
+   Helper function for selftests.  */
+
+static void
+verify_gimple_pp (const char *expected, gimple *stmt)
+{
+  pretty_printer pp;
+  pp_gimple_stmt_1 (&pp, stmt, 0 /* spc */, 0 /* flags */);
+  ASSERT_STREQ (expected, pp_formatted_text (&pp));
+}
+
+/* Build a GIMPLE_ASSIGN equivalent to
+     tmp = 5;
+   and verify various properties of it.  */
+
+static void
+test_assign_single ()
+{
+  tree type = integer_type_node;
+  tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			 get_identifier ("tmp"),
+			 type);
+  tree rhs = build_int_cst (type, 5);
+  gassign *stmt = gimple_build_assign (lhs, rhs);
+  verify_gimple_pp ("tmp = 5;", stmt);
+
+  ASSERT_TRUE (is_gimple_assign (stmt));
+  ASSERT_EQ (lhs, gimple_assign_lhs (stmt));
+  ASSERT_EQ (lhs, gimple_get_lhs (stmt));
+  ASSERT_EQ (rhs, gimple_assign_rhs1 (stmt));
+  ASSERT_EQ (NULL, gimple_assign_rhs2 (stmt));
+  ASSERT_EQ (NULL, gimple_assign_rhs3 (stmt));
+  ASSERT_TRUE (gimple_assign_single_p (stmt));
+  ASSERT_EQ (INTEGER_CST, gimple_assign_rhs_code (stmt));
+}
+
+/* Build a GIMPLE_ASSIGN equivalent to
+     tmp = a * b;
+   and verify various properties of it.  */
+
+static void
+test_assign_binop ()
+{
+  tree type = integer_type_node;
+  tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			 get_identifier ("tmp"),
+			 type);
+  tree a = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		       get_identifier ("a"),
+		       type);
+  tree b = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		       get_identifier ("b"),
+		       type);
+  gassign *stmt = gimple_build_assign (lhs, MULT_EXPR, a, b);
+  verify_gimple_pp ("tmp = a * b;", stmt);
+
+  ASSERT_TRUE (is_gimple_assign (stmt));
+  ASSERT_EQ (lhs, gimple_assign_lhs (stmt));
+  ASSERT_EQ (lhs, gimple_get_lhs (stmt));
+  ASSERT_EQ (a, gimple_assign_rhs1 (stmt));
+  ASSERT_EQ (b, gimple_assign_rhs2 (stmt));
+  ASSERT_EQ (NULL, gimple_assign_rhs3 (stmt));
+  ASSERT_FALSE (gimple_assign_single_p (stmt));
+  ASSERT_EQ (MULT_EXPR, gimple_assign_rhs_code (stmt));
+}
+
+/* Build a GIMPLE_NOP and verify various properties of it.  */
+
+static void
+test_nop_stmt ()
+{
+  gimple *stmt = gimple_build_nop ();
+  verify_gimple_pp ("GIMPLE_NOP", stmt);
+  ASSERT_EQ (GIMPLE_NOP, gimple_code (stmt));
+  ASSERT_EQ (NULL, gimple_get_lhs (stmt));
+  ASSERT_FALSE (gimple_assign_single_p (stmt));
+}
+
+/* Build a GIMPLE_RETURN equivalent to
+     return 7;
+   and verify various properties of it.  */
+
+static void
+test_return_stmt ()
+{
+  tree type = integer_type_node;
+  tree val = build_int_cst (type, 7);
+  greturn *stmt = gimple_build_return (val);
+  verify_gimple_pp ("return 7;", stmt);
+
+  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt));
+  ASSERT_EQ (NULL, gimple_get_lhs (stmt));
+  ASSERT_EQ (val, gimple_return_retval (stmt));
+  ASSERT_FALSE (gimple_assign_single_p (stmt));
+}
+
+/* Build a GIMPLE_RETURN equivalent to
+     return;
+   and verify various properties of it.  */
+
+static void
+test_return_without_value ()
+{
+  greturn *stmt = gimple_build_return (NULL);
+  verify_gimple_pp ("return;", stmt);
+
+  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt));
+  ASSERT_EQ (NULL, gimple_get_lhs (stmt));
+  ASSERT_EQ (NULL, gimple_return_retval (stmt));
+  ASSERT_FALSE (gimple_assign_single_p (stmt));
+}
+
+namespace selftest {
+
+/* Run all of the selftests within this file.  */
+
+void
+gimple_c_tests ()
+{
+  test_assign_single ();
+  test_assign_binop ();
+  test_nop_stmt ();
+  test_return_stmt ();
+  test_return_without_value ();
+}
+
+} // namespace selftest
+
+
+#endif /* CHECKING_P */
diff --git a/gcc/hash-map-tests.c b/gcc/hash-map-tests.c
new file mode 100644
index 0000000..663ec82
--- /dev/null
+++ b/gcc/hash-map-tests.c
@@ -0,0 +1,93 @@
+/* Unit tests for hash-map.h.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+/* Construct a hash_map <const char *, int> and verify that
+   various operations work correctly.  */
+
+static void
+test_map_of_strings_to_int ()
+{
+  hash_map <const char *, int> m;
+
+  const char *ostrich = "ostrich";
+  const char *elephant = "elephant";
+  const char *ant = "ant";
+  const char *spider = "spider";
+  const char *millipede = "Illacme plenipes";
+  const char *eric = "half a bee";
+
+  /* A fresh hash_map should be empty.  */
+  ASSERT_EQ (0, m.elements ());
+  ASSERT_EQ (NULL, m.get (ostrich));
+
+  /* Populate the hash_map.  */
+  ASSERT_EQ (false, m.put (ostrich, 2));
+  ASSERT_EQ (false, m.put (elephant, 4));
+  ASSERT_EQ (false, m.put (ant, 6));
+  ASSERT_EQ (false, m.put (spider, 8));
+  ASSERT_EQ (false, m.put (millipede, 750));
+  ASSERT_EQ (false, m.put (eric, 3));
+
+  /* Verify that we can recover the stored values.  */
+  ASSERT_EQ (6, m.elements ());
+  ASSERT_EQ (2, *m.get (ostrich));
+  ASSERT_EQ (4, *m.get (elephant));
+  ASSERT_EQ (6, *m.get (ant));
+  ASSERT_EQ (8, *m.get (spider));
+  ASSERT_EQ (750, *m.get (millipede));
+  ASSERT_EQ (3, *m.get (eric));
+
+  /* Verify removing an item.  */
+  m.remove (eric);
+  ASSERT_EQ (5, m.elements ());
+  ASSERT_EQ (NULL, m.get (eric));
+}
+
+namespace selftest {
+
+/* Run all of the selftests within this file.  */
+
+void
+hash_map_tests_c_tests ()
+{
+  test_map_of_strings_to_int ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
diff --git a/gcc/hash-set-tests.c b/gcc/hash-set-tests.c
new file mode 100644
index 0000000..1c7b7a1
--- /dev/null
+++ b/gcc/hash-set-tests.c
@@ -0,0 +1,69 @@
+/* Unit tests for hash-set.h.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+/* Construct a hash_set <const char *> and verify that various operations
+   work correctly.  */
+
+static void
+test_set_of_strings ()
+{
+  hash_set <const char *> s;
+  ASSERT_EQ (0, s.elements ());
+
+  const char *red = "red";
+  const char *green = "green";
+  const char *blue = "blue";
+
+  ASSERT_EQ (false, s.contains (red));
+
+  /* Populate the hash_set.  */
+  ASSERT_EQ (false, s.add (red));
+  ASSERT_EQ (false, s.add (green));
+  ASSERT_EQ (false, s.add (blue));
+
+  /* Verify that the values are now within the set.  */
+  ASSERT_EQ (true, s.contains (red));
+  ASSERT_EQ (true, s.contains (green));
+  ASSERT_EQ (true, s.contains (blue));
+}
+
+namespace selftest {
+
+/* Run all of the selftests within this file.  */
+
+void
+hash_set_tests_c_tests ()
+{
+  test_set_of_strings ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/input.c b/gcc/input.c
index 61b1e44..367901e 100644
--- a/gcc/input.c
+++ b/gcc/input.c
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "intl.h"
 #include "diagnostic-core.h"
+#include "selftest.h"
 
 /* This is a cache used by get_next_line to store the content of a
    file to be searched for file lines.  */
@@ -1136,3 +1137,120 @@ dump_location_info (FILE *stream)
   dump_labelled_location_range (stream, "AD-HOC LOCATIONS",
 				MAX_SOURCE_LOCATION + 1, UINT_MAX);
 }
+
+#if CHECKING_P
+
+/* Selftests of location handling.  */
+
+/* Verify the result of LOCATION_FILE/LOCATION_LINE/LOCATION_COLUMN
+   on LOC.  */
+
+static void
+assert_loceq (const char *exp_filename,
+	      int exp_linenum,
+	      int exp_colnum,
+	      location_t loc)
+{
+  ASSERT_STREQ (exp_filename, LOCATION_FILE (loc));
+  ASSERT_EQ (exp_linenum, LOCATION_LINE (loc));
+  ASSERT_EQ (exp_colnum, LOCATION_COLUMN (loc));
+}
+
+/* Verify basic operation of ordinary linemaps.  */
+
+static void
+test_accessing_ordinary_linemaps ()
+{
+  /* Build a simple linemap describing some locations. */
+  linemap_add (line_table, LC_ENTER, false, "foo.c", 0);
+
+  linemap_line_start (line_table, 1, 100);
+  location_t loc_a = linemap_position_for_column (line_table, 1);
+  location_t loc_b = linemap_position_for_column (line_table, 23);
+
+  linemap_line_start (line_table, 2, 100);
+  location_t loc_c = linemap_position_for_column (line_table, 1);
+  location_t loc_d = linemap_position_for_column (line_table, 17);
+
+  /* Example of a very long line.  */
+  linemap_line_start (line_table, 3, 2000);
+  location_t loc_e = linemap_position_for_column (line_table, 700);
+
+  linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+
+  /* Multiple files.  */
+  linemap_add (line_table, LC_ENTER, false, "bar.c", 0);
+  linemap_line_start (line_table, 1, 200);
+  location_t loc_f = linemap_position_for_column (line_table, 150);
+  linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+
+  /* Verify that we can recover the location info.  */
+  assert_loceq ("foo.c", 1, 1, loc_a);
+  assert_loceq ("foo.c", 1, 23, loc_b);
+  assert_loceq ("foo.c", 2, 1, loc_c);
+  assert_loceq ("foo.c", 2, 17, loc_d);
+  assert_loceq ("foo.c", 3, 700, loc_e);
+  assert_loceq ("bar.c", 1, 150, loc_f);
+
+  ASSERT_FALSE (is_location_from_builtin_token (loc_a));
+}
+
+/* Verify various properties of UNKNOWN_LOCATION.  */
+
+static void
+test_unknown_location ()
+{
+  ASSERT_EQ (NULL, LOCATION_FILE (UNKNOWN_LOCATION));
+  ASSERT_EQ (0, LOCATION_LINE (UNKNOWN_LOCATION));
+  ASSERT_EQ (0, LOCATION_COLUMN (UNKNOWN_LOCATION));
+}
+
+/* Verify various properties of BUILTINS_LOCATION.  */
+
+static void
+test_builtins ()
+{
+  assert_loceq ("<built-in>", 0, 0, BUILTINS_LOCATION);
+  ASSERT_PRED1 (is_location_from_builtin_token, BUILTINS_LOCATION);
+}
+
+/* Verify reading of input files (e.g. for caret-based diagnostics).  */
+
+static void
+test_reading_source_line ()
+{
+  /* We will read *this* source file, using __FILE__.
+     Here is some specific text to read and test for:
+     The quick brown fox jumps over the lazy dog.  */
+  const int linenum_after_test_message = __LINE__;
+  const int linenum = linenum_after_test_message - 1;
+
+  int line_size;
+  const char *source_line = location_get_source_line (__FILE__, linenum, &line_size);
+  ASSERT_TRUE (source_line != NULL);
+  ASSERT_EQ (53, line_size);
+  if (!strncmp ("     The quick brown fox jumps over the lazy dog.  */",
+	       source_line, line_size))
+    ::selftest::pass (__FILE__, __LINE__,
+		      "source_line matched expected value");
+  else
+    ::selftest::fail (__FILE__, __LINE__,
+		      "source_line did not match expected value");
+}
+
+namespace selftest {
+
+/* Run all of the selftests within this file.  */
+
+void
+input_c_tests ()
+{
+  test_accessing_ordinary_linemaps ();
+  test_unknown_location ();
+  test_builtins ();
+  test_reading_source_line ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
diff --git a/gcc/rtl-tests.c b/gcc/rtl-tests.c
new file mode 100644
index 0000000..a94ec5a
--- /dev/null
+++ b/gcc/rtl-tests.c
@@ -0,0 +1,117 @@
+/* Unit tests for RTL-handling.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "pretty-print.h"
+#include "cfgbuild.h"
+#include "print-rtl.h"
+#include "selftest.h"
+#include "function.h"
+#include "emit-rtl.h"
+
+#if CHECKING_P
+
+/* Verify that PAT is printed as EXPECTED.  Helper function for
+   selftests.  */
+
+static void
+verify_print_pattern (const char *expected, rtx pat)
+{
+  pretty_printer pp;
+  print_pattern (&pp, pat, 1);
+  ASSERT_STREQ (expected, pp_formatted_text (&pp));
+}
+
+/* Unit testing of "single_set".  */
+
+static void
+test_single_set ()
+{
+  /* A label is not a SET.  */
+  ASSERT_EQ (NULL_RTX, single_set (gen_label_rtx ()));
+
+  /* An unconditional jump insn is a single SET.  */
+  rtx set_pc = gen_rtx_SET (pc_rtx,
+			    gen_rtx_LABEL_REF (VOIDmode,
+					       gen_label_rtx ()));
+  rtx_insn *jump_insn = emit_jump_insn (set_pc);
+  ASSERT_EQ (set_pc, single_set (jump_insn));
+
+  /* etc */
+}
+
+/* Construct an unconditional jump to a label, and verify that
+   various properties of it are sane.  */
+
+static void
+test_uncond_jump ()
+{
+  rtx_insn *label = gen_label_rtx ();
+  rtx jump_pat = gen_rtx_SET (pc_rtx,
+			      gen_rtx_LABEL_REF (VOIDmode,
+						 label));
+  ASSERT_EQ (SET, jump_pat->code);
+  ASSERT_EQ (LABEL_REF, SET_SRC (jump_pat)->code);
+  ASSERT_EQ (label, LABEL_REF_LABEL (SET_SRC (jump_pat)));
+  ASSERT_EQ (PC, SET_DEST (jump_pat)->code);
+
+  verify_print_pattern ("pc=L0", jump_pat);
+
+  rtx_insn *jump_insn = emit_jump_insn (jump_pat);
+  ASSERT_FALSE (any_condjump_p (jump_insn));
+  ASSERT_TRUE (any_uncondjump_p (jump_insn));
+  ASSERT_TRUE (pc_set (jump_insn));
+  ASSERT_TRUE (simplejump_p (jump_insn));
+  ASSERT_TRUE (onlyjump_p (jump_insn));
+  ASSERT_TRUE (control_flow_insn_p (jump_insn));
+}
+
+namespace selftest {
+
+/* Run all of the selftests within this file.  */
+
+void
+rtl_tests_c_tests ()
+{
+  test_single_set ();
+  test_uncond_jump ();
+
+  /* Purge state.  */
+  set_first_insn (NULL);
+  set_last_insn (NULL);
+}
+
+} // namespace selftest
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
new file mode 100644
index 0000000..ab334aa
--- /dev/null
+++ b/gcc/selftest-run-tests.c
@@ -0,0 +1,77 @@
+/* Implementation of selftests.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "selftest.h"
+
+/* This function needed to be split out from selftest.c as it references
+   tests from the whole source tree, and so is within
+   OBJS in Makefile.in, whereas selftest.o is within OBJS-libcommon.
+   This allows us to embed tests within files in OBJS-libcommon without
+   introducing a dependency on objects within OBJS.  */
+
+#if CHECKING_P
+
+/* Run all tests, aborting if any fail.  */
+
+void
+selftest::run_tests ()
+{
+  long start_time = get_run_time ();
+
+  /* Run all the tests, in hand-coded order of (approximate) dependencies:
+     run the tests for lowest-level code first.  */
+
+  /* Low-level data structures.  */
+  bitmap_c_tests ();
+  et_forest_c_tests ();
+  hash_map_tests_c_tests ();
+  hash_set_tests_c_tests ();
+  vec_c_tests ();
+  wide_int_cc_tests ();
+
+  /* Mid-level data structures.  */
+  input_c_tests ();
+  tree_c_tests ();
+  gimple_c_tests ();
+  rtl_tests_c_tests ();
+
+  /* Higher-level tests, or for components that other selftests don't
+     rely on.  */
+  diagnostic_show_locus_c_tests ();
+  fold_const_c_tests ();
+  spellcheck_c_tests ();
+  tree_cfg_c_tests ();
+
+  /* This one relies on most of the above.  */
+  function_tests_c_tests ();
+
+  /* Finished running tests.  */
+  long finish_time = get_run_time ();
+  long elapsed_time = finish_time - start_time;
+
+  fprintf (stderr,
+	   "-fself-test: %i pass(es) in %ld.%06ld seconds\n",
+	   num_passes,
+	   elapsed_time / 1000000, elapsed_time % 1000000);
+}
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest.c b/gcc/selftest.c
new file mode 100644
index 0000000..de804df
--- /dev/null
+++ b/gcc/selftest.c
@@ -0,0 +1,47 @@
+/* A self-testing framework, for use by -fself-test.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+int selftest::num_passes;
+
+/* Record the successful outcome of some aspect of a test.  */
+
+void
+selftest::pass (const char */*file*/, int /*line*/, const char */*msg*/)
+{
+  num_passes++;
+}
+
+/* Report the failed outcome of some aspect of a test and abort.  */
+
+void
+selftest::fail (const char *file, int line, const char *msg)
+{
+  fprintf (stderr,"%s:%i: FAIL: %s\n", file, line, msg);
+  /* TODO: add calling function name as well?  */
+  abort ();
+}
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest.h b/gcc/selftest.h
new file mode 100644
index 0000000..a1d3074
--- /dev/null
+++ b/gcc/selftest.h
@@ -0,0 +1,153 @@
+/* A self-testing framework, for use by -fself-test.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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/>.  */
+
+#ifndef GCC_SELFTEST_H
+#define GCC_SELFTEST_H
+
+/* The selftest code should entirely disappear in a production
+   configuration, hence we guard all of it with #if CHECKING_P.  */
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* The entrypoint for running all tests.  */
+
+extern void run_tests ();
+
+/* Record the successful outcome of some aspect of the test.  */
+
+extern void pass (const char *file, int line, const char *msg);
+
+/* Report the failed outcome of some aspect of the test and abort.  */
+
+extern void fail (const char *file, int line, const char *msg);
+
+/* Declarations for specific families of tests (by source file), in
+   alphabetical order.  */
+extern void bitmap_c_tests ();
+extern void diagnostic_show_locus_c_tests ();
+extern void et_forest_c_tests ();
+extern void fold_const_c_tests ();
+extern void function_tests_c_tests ();
+extern void gimple_c_tests ();
+extern void hash_map_tests_c_tests ();
+extern void hash_set_tests_c_tests ();
+extern void input_c_tests ();
+extern void rtl_tests_c_tests ();
+extern void spellcheck_c_tests ();
+extern void tree_c_tests ();
+extern void tree_cfg_c_tests ();
+extern void vec_c_tests ();
+extern void wide_int_cc_tests ();
+
+extern int num_passes;
+
+} /* end of namespace selftest.  */
+
+/* Macros for writing tests.  */
+
+/* Evaluate EXPR and coerce to bool, calling
+   ::selftest::pass if it is true,
+   ::selftest::fail if it false.  */
+
+#define ASSERT_TRUE(EXPR)				\
+  SELFTEST_BEGIN_STMT					\
+  const char *desc = "ASSERT_TRUE (" #EXPR ")";		\
+  bool actual = (EXPR);					\
+  if (actual)						\
+    ::selftest::pass (__FILE__, __LINE__, desc);	\
+  else							\
+    ::selftest::fail (__FILE__, __LINE__, desc);		\
+  SELFTEST_END_STMT
+
+/* Evaluate EXPR and coerce to bool, calling
+   ::selftest::pass if it is false,
+   ::selftest::fail if it true.  */
+
+#define ASSERT_FALSE(EXPR)					\
+  SELFTEST_BEGIN_STMT						\
+  const char *desc = "ASSERT_FALSE (" #EXPR ")";		\
+  bool actual = (EXPR);					\
+  if (actual)							\
+    ::selftest::fail (__FILE__, __LINE__, desc);				\
+  else								\
+    ::selftest::pass (__FILE__, __LINE__, desc);				\
+  SELFTEST_END_STMT
+
+/* Evaluate EXPECTED and ACTUAL and compare them with ==, calling
+   ::selftest::pass if they are equal,
+   ::selftest::fail if they are non-equal.  */
+
+#define ASSERT_EQ(EXPECTED, ACTUAL)			       \
+  SELFTEST_BEGIN_STMT					       \
+  const char *desc = "ASSERT_EQ (" #EXPECTED ", " #ACTUAL ")"; \
+  if ((EXPECTED) == (ACTUAL))				       \
+    ::selftest::pass (__FILE__, __LINE__, desc);			       \
+  else							       \
+    ::selftest::fail (__FILE__, __LINE__, desc);			       \
+  SELFTEST_END_STMT
+
+/* Evaluate EXPECTED and ACTUAL and compare them with !=, calling
+   ::selftest::pass if they are non-equal,
+   ::selftest::fail if they are equal.  */
+
+#define ASSERT_NE(EXPECTED, ACTUAL)			       \
+  SELFTEST_BEGIN_STMT					       \
+  const char *desc = "ASSERT_NE (" #EXPECTED ", " #ACTUAL ")"; \
+  if ((EXPECTED) != (ACTUAL))				       \
+    ::selftest::pass (__FILE__, __LINE__, desc);			       \
+  else							       \
+    ::selftest::fail (__FILE__, __LINE__, desc);			       \
+  SELFTEST_END_STMT
+
+/* Evaluate EXPECTED and ACTUAL and compare them with strcmp, calling
+   ::selftest::pass if they are equal,
+   ::selftest::fail if they are non-equal.  */
+
+#define ASSERT_STREQ(EXPECTED, ACTUAL)			       \
+  SELFTEST_BEGIN_STMT					       \
+  const char *desc = "ASSERT_STREQ (" #EXPECTED ", " #ACTUAL ")"; \
+  const char *expected_ = (EXPECTED);				  \
+  const char *actual_ = (ACTUAL);				  \
+  if (0 == strcmp (expected_, actual_))				  \
+    ::selftest::pass (__FILE__, __LINE__, desc);			       \
+  else							       \
+    ::selftest::fail (__FILE__, __LINE__, desc);			       \
+  SELFTEST_END_STMT
+
+/* Evaluate PRED1 (VAL1), calling ::selftest::pass if it is true,
+   ::selftest::fail if it is false.  */
+
+#define ASSERT_PRED1(PRED1, VAL1)			\
+  SELFTEST_BEGIN_STMT					\
+  const char *desc = "ASSERT_PRED1 (" #PRED1 ", " #VAL1 ")";	\
+  bool actual = (PRED1) (VAL1);				\
+  if (actual)						\
+    ::selftest::pass (__FILE__, __LINE__, desc);			\
+  else							\
+    ::selftest::fail (__FILE__, __LINE__, desc);			\
+  SELFTEST_END_STMT
+
+#define SELFTEST_BEGIN_STMT do {
+#define SELFTEST_END_STMT   } while (0)
+
+#endif /* #if CHECKING_P */
+
+#endif /* GCC_SELFTEST_H */
diff --git a/gcc/spellcheck.c b/gcc/spellcheck.c
index e4e83a5..5ac5c60 100644
--- a/gcc/spellcheck.c
+++ b/gcc/spellcheck.c
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "tree.h"
 #include "spellcheck.h"
+#include "selftest.h"
 
 /* The Levenshtein distance is an "edit-distance": the minimal
    number of one-character insertions, removals or substitutions
@@ -165,3 +166,60 @@ find_closest_string (const char *target,
 
   return best_candidate;
 }
+
+#if CHECKING_P
+
+/* Selftests.  */
+
+/* Verify that the levenshtein_distance (A, B) equals the expected
+   value.  */
+
+static void
+levenshtein_distance_unit_test_oneway (const char *a, const char *b,
+				       edit_distance_t expected)
+{
+  edit_distance_t actual = levenshtein_distance (a, b);
+  ASSERT_EQ (actual, expected);
+}
+
+/* Verify that both
+     levenshtein_distance (A, B)
+   and
+     levenshtein_distance (B, A)
+   equal the expected value, to ensure that the function is symmetric.  */
+
+static void
+levenshtein_distance_unit_test (const char *a, const char *b,
+				edit_distance_t expected)
+{
+  levenshtein_distance_unit_test_oneway (a, b, expected);
+  levenshtein_distance_unit_test_oneway (b, a, expected);
+}
+
+namespace selftest {
+
+/* Verify levenshtein_distance for a variety of pairs of pre-canned
+   inputs, comparing against known-good values.  */
+
+void
+spellcheck_c_tests ()
+{
+  levenshtein_distance_unit_test ("", "nonempty", strlen ("nonempty"));
+  levenshtein_distance_unit_test ("saturday", "sunday", 3);
+  levenshtein_distance_unit_test ("foo", "m_foo", 2);
+  levenshtein_distance_unit_test ("hello_world", "HelloWorld", 3);
+  levenshtein_distance_unit_test
+    ("the quick brown fox jumps over the lazy dog", "dog", 40);
+  levenshtein_distance_unit_test
+    ("the quick brown fox jumps over the lazy dog",
+     "the quick brown dog jumps over the lazy fox",
+     4);
+  levenshtein_distance_unit_test
+    ("Lorem ipsum dolor sit amet, consectetur adipiscing elit,",
+     "All your base are belong to us",
+     44);
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c b/gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c
deleted file mode 100644
index ac49992..0000000
--- a/gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c
+++ /dev/null
@@ -1,9 +0,0 @@
-/* Placeholder C source file for unit-testing gcc/spellcheck.c.  */
-/* { dg-do compile } */
-/* { dg-options "-O" } */
-
-int
-main (int argc, char **argv)
-{
-  return 0;
-}
diff --git a/gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c b/gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c
deleted file mode 100644
index 3e7dc78..0000000
--- a/gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Plugin for unittesting gcc/spellcheck.h.  */
-
-#include "config.h"
-#include "gcc-plugin.h"
-#include "system.h"
-#include "coretypes.h"
-#include "spellcheck.h"
-#include "diagnostic.h"
-
-int plugin_is_GPL_compatible;
-
-static void
-levenshtein_distance_unit_test_oneway (const char *a, const char *b,
-				       edit_distance_t expected)
-{
-  edit_distance_t actual = levenshtein_distance (a, b);
-  if (actual != expected)
-    error ("levenshtein_distance (\"%s\", \"%s\") : expected: %i got %i",
-	   a, b, expected, actual);
-}
-
-
-static void
-levenshtein_distance_unit_test (const char *a, const char *b,
-				edit_distance_t expected)
-{
-  /* Run every test both ways to ensure it's symmetric.  */
-  levenshtein_distance_unit_test_oneway (a, b, expected);
-  levenshtein_distance_unit_test_oneway (b, a, expected);
-}
-
-/* Callback handler for the PLUGIN_FINISH event; run
-   levenshtein_distance unit tests here.  */
-
-static void
-on_finish (void */*gcc_data*/, void */*user_data*/)
-{
-  levenshtein_distance_unit_test ("", "nonempty", strlen ("nonempty"));
-  levenshtein_distance_unit_test ("saturday", "sunday", 3);
-  levenshtein_distance_unit_test ("foo", "m_foo", 2);
-  levenshtein_distance_unit_test ("hello_world", "HelloWorld", 3);
-  levenshtein_distance_unit_test
-    ("the quick brown fox jumps over the lazy dog", "dog", 40);
-  levenshtein_distance_unit_test
-    ("the quick brown fox jumps over the lazy dog",
-     "the quick brown dog jumps over the lazy fox",
-     4);
-  levenshtein_distance_unit_test
-    ("Lorem ipsum dolor sit amet, consectetur adipiscing elit,",
-     "All your base are belong to us",
-     44);
-}
-
-int
-plugin_init (struct plugin_name_args *plugin_info,
-	     struct plugin_gcc_version */*version*/)
-{
-  register_callback (plugin_info->base_name,
-		     PLUGIN_FINISH,
-		     on_finish,
-		     NULL); /* void *user_data */
-
-  return 0;
-}
diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp
index 321b4ba..be2ac8d 100644
--- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
+++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
@@ -70,7 +70,6 @@ set plugin_test_list [list \
 	  diagnostic-test-expressions-1.c } \
     { diagnostic_plugin_show_trees.c \
 	  diagnostic-test-show-trees-1.c } \
-    { levenshtein_plugin.c levenshtein-test-1.c } \
     { location_overflow_plugin.c \
 	  location-overflow-test-1.c \
 	  location-overflow-test-2.c } \
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 230878e..543b8a3 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -87,6 +87,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "xcoffout.h"		/* Needed for external data declarations. */
 #endif
 
+#include "selftest.h"
+
 static void general_init (const char *, bool);
 static void do_compile ();
 static void process_options (void);
@@ -2031,6 +2033,27 @@ toplev::start_timevars ()
   timevar_start (TV_TOTAL);
 }
 
+/* Handle -fself-test.   */
+
+void
+toplev::run_self_tests ()
+{
+#if CHECKING_P
+  /* Reset some state.  */
+  input_location = UNKNOWN_LOCATION;
+  bitmap_obstack_initialize (NULL);
+
+  /* Run the tests; any failures will lead to an abort of the process.
+     Use "make selftests-gdb" to run under the debugger.  */
+  ::selftest::run_tests ();
+
+  /* Cleanup.  */
+  bitmap_obstack_release (NULL);
+#else
+  inform (UNKNOWN_LOCATION, "self-tests are not enabled in this build");
+#endif /* #if CHECKING_P */
+}
+
 /* Entry point of cc1, cc1plus, jc1, f771, etc.
    Exit code is FATAL_EXIT_CODE if can't open files or if there were
    any errors, or SUCCESS_EXIT_CODE if compilation succeeded.
@@ -2098,6 +2121,9 @@ toplev::main (int argc, char **argv)
   if (warningcount || errorcount || werrorcount)
     print_ignored_options ();
 
+  if (flag_self_test)
+    run_self_tests ();
+
   /* Invoke registered plugin callbacks if any.  Some plugins could
      emit some diagnostics here.  */
   invoke_plugin_callbacks (PLUGIN_FINISH, NULL);
diff --git a/gcc/toplev.h b/gcc/toplev.h
index 0beb06e..06923cf 100644
--- a/gcc/toplev.h
+++ b/gcc/toplev.h
@@ -42,6 +42,8 @@ private:
 
   void start_timevars ();
 
+  void run_self_tests ();
+
   bool m_use_TV_TOTAL;
   bool m_init_signals;
 };
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 7fc24ba..ddf594d 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -58,6 +58,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-cfgcleanup.h"
 #include "gimplify.h"
 #include "attribs.h"
+#include "selftest.h"
 
 /* This file contains functions for building the Control Flow Graph (CFG)
    for a function tree.  */
@@ -9195,3 +9196,281 @@ gt_pch_nx (edge_def *e, gt_pointer_operator op, void *cookie)
     op (&(e->insns.r), cookie);
   op (&(block), cookie);
 }
+
+#if CHECKING_P
+
+/* Helper function for CFG selftests: create a dummy function decl
+   and push it as cfun.  */
+
+static tree
+push_fndecl (const char *name)
+{
+  tree fn_type = build_function_type_array (integer_type_node, /* return_type */
+					    0, NULL);
+  /* FIXME: this uses input_location: */
+  tree fndecl = build_fn_decl (name, fn_type);
+  tree retval = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+			    NULL_TREE, integer_type_node);
+  DECL_RESULT (fndecl) = retval;
+  push_struct_function (fndecl);
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  init_empty_tree_cfg_for_function (fun);
+  ASSERT_EQ (2, n_basic_blocks_for_fn (fun));
+  ASSERT_EQ (0, n_edges_for_fn (fun));
+  return fndecl;
+}
+
+/* These tests directly create CFGs.
+   Compare with the static fns within tree-cfg.c:
+     - build_gimple_cfg
+     - make_blocks: calls create_basic_block (seq, bb);
+     - make_edges.   */
+
+/* Verify a simple cfg of the form:
+     ENTRY -> A -> B -> C -> EXIT.  */
+
+static void
+test_linear_chain ()
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_test_linear_chain");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+
+  /* Create some empty blocks.  */
+  basic_block bb_a = create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun));
+  basic_block bb_b = create_empty_bb (bb_a);
+  basic_block bb_c = create_empty_bb (bb_b);
+
+  ASSERT_EQ (5, n_basic_blocks_for_fn (fun));
+  ASSERT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create some edges: a simple linear chain of BBs.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), bb_a, EDGE_FALLTHRU);
+  make_edge (bb_a, bb_b, 0);
+  make_edge (bb_b, bb_c, 0);
+  make_edge (bb_c, EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+
+  /* Verify the edges.  */
+  ASSERT_EQ (4, n_edges_for_fn (fun));
+  ASSERT_EQ (NULL, ENTRY_BLOCK_PTR_FOR_FN (fun)->preds);
+  ASSERT_EQ (1, ENTRY_BLOCK_PTR_FOR_FN (fun)->succs->length ());
+  ASSERT_EQ (1, bb_a->preds->length ());
+  ASSERT_EQ (1, bb_a->succs->length ());
+  ASSERT_EQ (1, bb_b->preds->length ());
+  ASSERT_EQ (1, bb_b->succs->length ());
+  ASSERT_EQ (1, bb_c->preds->length ());
+  ASSERT_EQ (1, bb_c->succs->length ());
+  ASSERT_EQ (1, EXIT_BLOCK_PTR_FOR_FN (fun)->preds->length ());
+  ASSERT_EQ (NULL, EXIT_BLOCK_PTR_FOR_FN (fun)->succs);
+
+  /* Verify the dominance information
+     Each BB in our simple chain should be dominated by the one before
+     it.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
+  ASSERT_EQ (bb_b, get_immediate_dominator (CDI_DOMINATORS, bb_c));
+  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
+  ASSERT_EQ (1, dom_by_b.length ());
+  ASSERT_EQ (bb_c, dom_by_b[0]);
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance: each BB in our chain is post-dominated
+     by the one after it.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  ASSERT_EQ (bb_b, get_immediate_dominator (CDI_POST_DOMINATORS, bb_a));
+  ASSERT_EQ (bb_c, get_immediate_dominator (CDI_POST_DOMINATORS, bb_b));
+  vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
+  ASSERT_EQ (1, postdom_by_b.length ());
+  ASSERT_EQ (bb_a, postdom_by_b[0]);
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+/* Verify a simple CFG of the form:
+     ENTRY
+       |
+       A
+      / \
+     /t  \f
+    B     C
+     \   /
+      \ /
+       D
+       |
+      EXIT.  */
+
+static void
+test_diamond ()
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_test_diamond");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+
+  /* Create some empty blocks.  */
+  basic_block bb_a = create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun));
+  basic_block bb_b = create_empty_bb (bb_a);
+  basic_block bb_c = create_empty_bb (bb_a);
+  basic_block bb_d = create_empty_bb (bb_b);
+
+  ASSERT_EQ (6, n_basic_blocks_for_fn (fun));
+  ASSERT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create the edges.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), bb_a, EDGE_FALLTHRU);
+  make_edge (bb_a, bb_b, EDGE_TRUE_VALUE);
+  make_edge (bb_a, bb_c, EDGE_FALSE_VALUE);
+  make_edge (bb_b, bb_d, 0);
+  make_edge (bb_c, bb_d, 0);
+  make_edge (bb_d, EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+
+  /* Verify the edges.  */
+  ASSERT_EQ (6, n_edges_for_fn (fun));
+  ASSERT_EQ (1, bb_a->preds->length ());
+  ASSERT_EQ (2, bb_a->succs->length ());
+  ASSERT_EQ (1, bb_b->preds->length ());
+  ASSERT_EQ (1, bb_b->succs->length ());
+  ASSERT_EQ (1, bb_c->preds->length ());
+  ASSERT_EQ (1, bb_c->succs->length ());
+  ASSERT_EQ (2, bb_d->preds->length ());
+  ASSERT_EQ (1, bb_d->succs->length ());
+
+  /* Verify the dominance information.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
+  ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_c));
+  ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_d));
+  vec<basic_block> dom_by_a = get_dominated_by (CDI_DOMINATORS, bb_a);
+  ASSERT_EQ (3, dom_by_a.length ()); /* B, C, D, in some order.  */
+  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
+  ASSERT_EQ (0, dom_by_b.length ());
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_a));
+  ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_b));
+  ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_c));
+  vec<basic_block> postdom_by_d = get_dominated_by (CDI_POST_DOMINATORS, bb_d);
+  ASSERT_EQ (3, postdom_by_d.length ()); /* A, B, C in some order.  */
+  vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
+  ASSERT_EQ (0, postdom_by_b.length ());
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+/* Verify that we can handle a CFG containing a "complete" aka
+   fully-connected subgraph (where A B C D below all have edges
+   pointing to each other node, also to themselves).
+   e.g.:
+     ENTRY  EXIT
+       |    ^
+       |   /
+       |  /
+       | /
+       V/
+       A<--->B
+       ^^   ^^
+       | \ / |
+       |  X  |
+       | / \ |
+       VV   VV
+       C<--->D
+*/
+
+static void
+test_fully_connected ()
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_fully_connected");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+
+  const int n = 4;
+
+  /* Create some empty blocks.  */
+  auto_vec <basic_block> subgraph_nodes;
+  for (int i = 0; i < n; i++)
+    subgraph_nodes.safe_push (create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun)));
+
+  ASSERT_EQ (n + 2, n_basic_blocks_for_fn (fun));
+  ASSERT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create the edges.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), subgraph_nodes[0], EDGE_FALLTHRU);
+  make_edge (subgraph_nodes[0], EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+  for (int i = 0; i < n; i++)
+    for (int j = 0; j < n; j++)
+      make_edge (subgraph_nodes[i], subgraph_nodes[j], 0);
+
+  /* Verify the edges.  */
+  ASSERT_EQ (2 + (n * n), n_edges_for_fn (fun));
+  /* The first one is linked to ENTRY/EXIT as well as itself and
+     everything else.  */
+  ASSERT_EQ (n + 1, subgraph_nodes[0]->preds->length ());
+  ASSERT_EQ (n + 1, subgraph_nodes[0]->succs->length ());
+  /* The other ones in the subgraph are linked to everything in
+     the subgraph (including themselves).  */
+  for (int i = 1; i < n; i++)
+    {
+      ASSERT_EQ (n, subgraph_nodes[i]->preds->length ());
+      ASSERT_EQ (n, subgraph_nodes[i]->succs->length ());
+    }
+
+  /* Verify the dominance information.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  /* The initial block in the subgraph should be dominated by ENTRY.  */
+  ASSERT_EQ (ENTRY_BLOCK_PTR_FOR_FN (fun),
+	     get_immediate_dominator (CDI_DOMINATORS,
+				      subgraph_nodes[0]));
+  /* Every other block in the subgraph should be dominated by the
+     initial block.  */
+  for (int i = 1; i < n; i++)
+    ASSERT_EQ (subgraph_nodes[0],
+	       get_immediate_dominator (CDI_DOMINATORS,
+					subgraph_nodes[i]));
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  /* The initial block in the subgraph should be postdominated by EXIT.  */
+  ASSERT_EQ (EXIT_BLOCK_PTR_FOR_FN (fun),
+	     get_immediate_dominator (CDI_POST_DOMINATORS,
+				      subgraph_nodes[0]));
+  /* Every other block in the subgraph should be postdominated by the
+     initial block, since that leads to EXIT.  */
+  for (int i = 1; i < n; i++)
+    ASSERT_EQ (subgraph_nodes[0],
+	       get_immediate_dominator (CDI_POST_DOMINATORS,
+					subgraph_nodes[i]));
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+namespace selftest {
+
+/* Run all of the selftests within this file.  */
+
+void
+tree_cfg_c_tests ()
+{
+  test_linear_chain ();
+  test_diamond ();
+  test_fully_connected ();
+}
+
+} // namespace selftest
+
+/* TODO: test the dominator/postdominator logic with various graphs/nodes:
+   - loop
+   - nested loops
+   - switch statement (a block with many out-edges)
+   - something that jumps to itself
+   - etc  */
+
+#endif /* CHECKING_P */
diff --git a/gcc/tree.c b/gcc/tree.c
index 2e01eac..4a45276 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -61,6 +61,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "print-tree.h"
 #include "ipa-utils.h"
+#include "selftest.h"
 
 /* Tree code classes.  */
 
@@ -14203,4 +14204,65 @@ combined_fn_name (combined_fn fn)
     return internal_fn_name (as_internal_fn (fn));
 }
 
+#if CHECKING_P
+
+/* Selftests for tree.  */
+
+/* Verify that integer constants are sane.  */
+
+static void
+test_integer_constants ()
+{
+  ASSERT_TRUE (integer_type_node != NULL);
+  ASSERT_TRUE (build_int_cst (integer_type_node, 0) != NULL);
+
+  tree type = integer_type_node;
+
+  tree zero = build_zero_cst (type);
+  ASSERT_EQ (INTEGER_CST, TREE_CODE (zero));
+  ASSERT_EQ (type, TREE_TYPE (zero));
+
+  tree one = build_int_cst (type, 1);
+  ASSERT_EQ (INTEGER_CST, TREE_CODE (one));
+  ASSERT_EQ (type, TREE_TYPE (zero));
+}
+
+/* Verify identifiers.  */
+
+static void
+test_identifiers ()
+{
+  tree identifier = get_identifier ("foo");
+  ASSERT_EQ (3, IDENTIFIER_LENGTH (identifier));
+  ASSERT_STREQ ("foo", IDENTIFIER_POINTER (identifier));
+}
+
+/* Verify LABEL_DECL.  */
+
+static void
+test_labels ()
+{
+  tree identifier = get_identifier ("err");
+  tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
+				identifier, void_type_node);
+  ASSERT_EQ (-1, LABEL_DECL_UID (label_decl));
+  ASSERT_FALSE (FORCED_LABEL (label_decl));
+}
+
+namespace selftest {
+
+/* Run all of the selftests within this file.  */
+
+void
+tree_c_tests ()
+{
+  test_integer_constants ();
+  test_identifiers ();
+  test_labels ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
+
 #include "gt-tree.h"
diff --git a/gcc/vec.c b/gcc/vec.c
index a483d5b..ef38f6ab 100644
--- a/gcc/vec.c
+++ b/gcc/vec.c
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "hash-table.h"
+#include "selftest.h"
 
 /* vNULL is an empty type with a template cast operation that returns
    a zero-initialized vec<T, A, L> instance.  Use this when you want
@@ -188,3 +189,194 @@ dump_vec_loc_statistics (void)
 {
   vec_mem_desc.dump (VEC_ORIGIN);
 }
+
+#ifndef GENERATOR_FILE
+#if CHECKING_P
+
+/* Selftests.  */
+
+/* Call V.safe_push for all ints from START up to, but not including LIMIT.
+   Helper function for selftests.  */
+
+static void
+safe_push_range (vec <int>&v, int start, int limit)
+{
+  for (int i = start; i < limit; i++)
+    v.safe_push (i);
+}
+
+/* Verify that vec::quick_push works correctly.  */
+
+static void
+test_quick_push ()
+{
+  auto_vec <int> v;
+  ASSERT_EQ (0, v.length ());
+  v.reserve (3);
+  ASSERT_EQ (0, v.length ());
+  ASSERT_TRUE (v.space (3));
+  v.quick_push (5);
+  v.quick_push (6);
+  v.quick_push (7);
+  ASSERT_EQ (3, v.length ());
+  ASSERT_EQ (5, v[0]);
+  ASSERT_EQ (6, v[1]);
+  ASSERT_EQ (7, v[2]);
+}
+
+/* Verify that vec::safe_push works correctly.  */
+
+static void
+test_safe_push ()
+{
+  auto_vec <int> v;
+  ASSERT_EQ (0, v.length ());
+  v.safe_push (5);
+  v.safe_push (6);
+  v.safe_push (7);
+  ASSERT_EQ (3, v.length ());
+  ASSERT_EQ (5, v[0]);
+  ASSERT_EQ (6, v[1]);
+  ASSERT_EQ (7, v[2]);
+}
+
+/* Verify that vec::truncate works correctly.  */
+
+static void
+test_truncate ()
+{
+  auto_vec <int> v;
+  ASSERT_EQ (0, v.length ());
+  safe_push_range (v, 0, 10);
+  ASSERT_EQ (10, v.length ());
+
+  v.truncate (5);
+  ASSERT_EQ (5, v.length ());
+}
+
+/* Verify that vec::safe_grow_cleared works correctly.  */
+
+static void
+test_safe_grow_cleared ()
+{
+  auto_vec <int> v;
+  ASSERT_EQ (0, v.length ());
+  v.safe_grow_cleared (50);
+  ASSERT_EQ (50, v.length ());
+  ASSERT_EQ (0, v[0]);
+  ASSERT_EQ (0, v[49]);
+}
+
+/* Verify that vec::pop works correctly.  */
+
+static void
+test_pop ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 5, 20);
+  ASSERT_EQ (15, v.length ());
+
+  int last = v.pop ();
+  ASSERT_EQ (19, last);
+  ASSERT_EQ (14, v.length ());
+}
+
+/* Verify that vec::safe_insert works correctly.  */
+
+static void
+test_safe_insert ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.safe_insert (5, 42);
+  ASSERT_EQ (4, v[4]);
+  ASSERT_EQ (42, v[5]);
+  ASSERT_EQ (5, v[6]);
+  ASSERT_EQ (11, v.length ());
+}
+
+/* Verify that vec::ordered_remove works correctly.  */
+
+static void
+test_ordered_remove ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.ordered_remove (5);
+  ASSERT_EQ (4, v[4]);
+  ASSERT_EQ (6, v[5]);
+  ASSERT_EQ (9, v.length ());
+}
+
+/* Verify that vec::unordered_remove works correctly.  */
+
+static void
+test_unordered_remove ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.unordered_remove (5);
+  ASSERT_EQ (9, v.length ());
+}
+
+/* Verify that vec::block_remove works correctly.  */
+
+static void
+test_block_remove ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.block_remove (5, 3);
+  ASSERT_EQ (3, v[3]);
+  ASSERT_EQ (4, v[4]);
+  ASSERT_EQ (8, v[5]);
+  ASSERT_EQ (9, v[6]);
+  ASSERT_EQ (7, v.length ());
+}
+
+/* Comparator for use by test_qsort.  */
+
+static int
+reverse_cmp (const void *p_i, const void *p_j)
+{
+  return *(const int *)p_j - *(const int *)p_i;
+}
+
+/* Verify that vec::qsort works correctly.  */
+
+static void
+test_qsort ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.qsort (reverse_cmp);
+  ASSERT_EQ (9, v[0]);
+  ASSERT_EQ (8, v[1]);
+  ASSERT_EQ (1, v[8]);
+  ASSERT_EQ (0, v[9]);
+  ASSERT_EQ (10, v.length ());
+}
+
+namespace selftest {
+
+/* Run all of the selftests within this file.  */
+
+void
+vec_c_tests ()
+{
+  test_quick_push ();
+  test_safe_push ();
+  test_truncate ();
+  test_safe_grow_cleared ();
+  test_pop ();
+  test_safe_insert ();
+  test_ordered_remove ();
+  test_unordered_remove ();
+  test_block_remove ();
+  test_qsort ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
+#endif /* #ifndef GENERATOR_FILE */
diff --git a/gcc/wide-int.cc b/gcc/wide-int.cc
index 8648e7d..310b3df 100644
--- a/gcc/wide-int.cc
+++ b/gcc/wide-int.cc
@@ -23,6 +23,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
+#include "selftest.h"
+#include "wide-int-print.h"
 
 
 #define HOST_BITS_PER_HALF_WIDE_INT 32
@@ -2144,3 +2146,171 @@ template void generic_wide_int <wide_int_ref_storage <false> >::dump () const;
 template void generic_wide_int <wide_int_ref_storage <true> >::dump () const;
 template void offset_int::dump () const;
 template void widest_int::dump () const;
+
+
+#if CHECKING_P
+
+/* Selftests for wide ints.  We run these multiple times, once per type.  */
+
+/* Helper function for building a test value.  */
+
+template <class VALUE_TYPE>
+static VALUE_TYPE
+from_int (int i);
+
+/* Specializations of the fixture for each wide-int type.  */
+
+/* Specialization for VALUE_TYPE == wide_int.  */
+
+template <>
+wide_int
+from_int (int i)
+{
+  return wi::shwi (i, 32);
+}
+
+/* Specialization for VALUE_TYPE == offset_int.  */
+
+template <>
+offset_int
+from_int (int i)
+{
+  return offset_int (i);
+}
+
+/* Specialization for VALUE_TYPE == widest_int.  */
+
+template <>
+widest_int
+from_int (int i)
+{
+  return widest_int (i);
+}
+
+/* Verify that print_dec (WI, ..., SGN) gives the expected string
+   representation (using base 10).  */
+
+static void
+assert_deceq (const char *expected, const wide_int_ref &wi, signop sgn)
+{
+  char buf[WIDE_INT_PRINT_BUFFER_SIZE];
+  print_dec (wi, buf, sgn);
+  ASSERT_STREQ (expected, buf);
+}
+
+/* Likewise for base 16.  */
+
+static void
+assert_hexeq (const char *expected, const wide_int_ref &wi)
+{
+  char buf[WIDE_INT_PRINT_BUFFER_SIZE];
+  print_hex (wi, buf);
+  ASSERT_STREQ (expected, buf);
+}
+
+/* Test cases.  */
+
+/* Verify that print_dec and print_hex work for VALUE_TYPE.  */
+
+template <class VALUE_TYPE>
+static void
+test_printing ()
+{
+  VALUE_TYPE a = from_int<VALUE_TYPE> (42);
+  assert_deceq ("42", a, SIGNED);
+  assert_hexeq ("0x2a", a);
+}
+
+/* Verify that various operations work correctly for VALUE_TYPE,
+   unary and binary, using both function syntax, and
+   overloaded-operators.  */
+
+template <class VALUE_TYPE>
+static void
+test_ops ()
+{
+  VALUE_TYPE a = from_int<VALUE_TYPE> (7);
+  VALUE_TYPE b = from_int<VALUE_TYPE> (3);
+
+  /* Using functions.  */
+  assert_deceq ("-7", wi::neg (a), SIGNED);
+  assert_deceq ("10", wi::add (a, b), SIGNED);
+  assert_deceq ("4", wi::sub (a, b), SIGNED);
+  assert_deceq ("-4", wi::sub (b, a), SIGNED);
+  assert_deceq ("21", wi::mul (a, b), SIGNED);
+
+  /* Using operators.  */
+  assert_deceq ("-7", -a, SIGNED);
+  assert_deceq ("10", a + b, SIGNED);
+  assert_deceq ("4", a - b, SIGNED);
+  assert_deceq ("-4", b - a, SIGNED);
+  assert_deceq ("21", a * b, SIGNED);
+}
+
+/* Verify that various comparisons work correctly for VALUE_TYPE.  */
+
+template <class VALUE_TYPE>
+static void
+test_comparisons ()
+{
+  VALUE_TYPE a = from_int<VALUE_TYPE> (7);
+  VALUE_TYPE b = from_int<VALUE_TYPE> (3);
+
+  /* == */
+  ASSERT_TRUE (wi::eq_p (a, a));
+  ASSERT_FALSE (wi::eq_p (a, b));
+
+  /* != */
+  ASSERT_TRUE (wi::ne_p (a, b));
+  ASSERT_FALSE (wi::ne_p (a, a));
+
+  /* < */
+  ASSERT_FALSE (wi::lts_p (a, a));
+  ASSERT_FALSE (wi::lts_p (a, b));
+  ASSERT_TRUE (wi::lts_p (b, a));
+
+  /* <= */
+  ASSERT_TRUE (wi::les_p (a, a));
+  ASSERT_FALSE (wi::les_p (a, b));
+  ASSERT_TRUE (wi::les_p (b, a));
+
+  /* > */
+  ASSERT_FALSE (wi::gts_p (a, a));
+  ASSERT_TRUE (wi::gts_p (a, b));
+  ASSERT_FALSE (wi::gts_p (b, a));
+
+  /* >= */
+  ASSERT_TRUE (wi::ges_p (a, a));
+  ASSERT_TRUE (wi::ges_p (a, b));
+  ASSERT_FALSE (wi::ges_p (b, a));
+
+  /* comparison */
+  ASSERT_EQ (-1, wi::cmps (b, a));
+  ASSERT_EQ (0, wi::cmps (a, a));
+  ASSERT_EQ (1, wi::cmps (a, b));
+}
+
+/* Run all of the selftests, using the given VALUE_TYPE.  */
+
+template <class VALUE_TYPE>
+static void run_all_wide_int_tests ()
+{
+  test_printing <VALUE_TYPE> ();
+  test_ops <VALUE_TYPE> ();
+  test_comparisons <VALUE_TYPE> ();
+}
+
+namespace selftest {
+
+/* Run all of the selftests within this file, for all value types.  */
+
+void
+wide_int_cc_tests ()
+{
+ run_all_wide_int_tests <wide_int> ();
+ run_all_wide_int_tests <offset_int> ();
+ run_all_wide_int_tests <widest_int> ();
+}
+
+} // namespace selftest
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH] Selftest framework (v7)
  2016-06-03 18:47                                     ` [PATCH] Selftest framework (v7) David Malcolm
@ 2016-06-05 11:38                                       ` Bernd Schmidt
  2016-06-06 14:17                                         ` David Malcolm
  0 siblings, 1 reply; 176+ messages in thread
From: Bernd Schmidt @ 2016-06-05 11:38 UTC (permalink / raw)
  To: David Malcolm, gcc-patches; +Cc: Bernd Schmidt, Jeff Law

On 06/03/2016 09:12 PM, David Malcolm wrote:
> It's not clear to me if these approvals still hold.

I was willing to go with it; I had a look through some of these patches 
and didn't spot anything untoward. To make it clear, this patch is OK, 
with one tweak if possible: extend the namespace selftest to cover the 
various helper functions (some of these have names like from_int which 
ideally we wouldn't leak into the rest of the compiler). As far as I can 
tell this just involves moving the start of namespace selftest upwards a 
bit in the files where we have tests.

A few other minor things...

> +  tree bind_expr =
> +    build3 (BIND_EXPR, void_type_node, NULL, stmt_list, block);

Operators go at the start of the line.

> +  tree fn_type = build_function_type_array (integer_type_node, /* return_type */

The line is too long, and we don't do /* arg name */ anyway.

> +static void
> +assert_loceq (const char *exp_filename,
> +	      int exp_linenum,
> +	      int exp_colnum,
> +	      location_t loc)

> +static layout_range
> +make_range (int start_line, int start_col,
> +	    int end_line, int end_col)

These lines are too short :) Could save some vertical space here.

For the future - I found the single merged patch easier to deal with 
than the 16- or 21-patch series. Split ups are often good when modifying 
the same code in multiple logically independent steps (keeping in mind 
that bugfixes to newly added code shouldn't be split out either). This 
is a different situation where the patches weren't truly independent, 
and the merged patch is essentially just a concatenation, so splitting 
it up does not really make the review any easier (potentially harder if 
you have to switch between mails rather than just hitting PgUp/Dn.


Bernd

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH] Selftest framework (v7)
  2016-06-05 11:38                                       ` Bernd Schmidt
@ 2016-06-06 14:17                                         ` David Malcolm
  2016-06-06 14:41                                           ` Bernd Schmidt
  2016-06-06 21:47                                           ` [PATCH] Selftest framework (v7) Trevor Saunders
  0 siblings, 2 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-06 14:17 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches; +Cc: Bernd Schmidt, Jeff Law

On Sun, 2016-06-05 at 13:37 +0200, Bernd Schmidt wrote:
> On 06/03/2016 09:12 PM, David Malcolm wrote:
> > It's not clear to me if these approvals still hold.
> 
> I was willing to go with it; I had a look through some of these
> patches 
> and didn't spot anything untoward. To make it clear, this patch is
> OK, 
> with one tweak if possible: extend the namespace selftest to cover
> the 
> various helper functions (some of these have names like from_int
> which 
> ideally we wouldn't leak into the rest of the compiler). 

I believe that apart from the from_int specializations, everything else
is marked with "static" (we can't mark template specializations with
"static").


> As far as I can 
> tell this just involves moving the start of namespace selftest
> upwards a 
> bit in the files where we have tests.

Yes, and it does seem cleaner to have all of the selftest code start
like this:

  #if CHECKING_P

  namespace selftest {

I'll make that change, apart from in diagnostic-show-locus.c, where the test functions are already within an anonymous namespace (the one containing the implementation).

> A few other minor things...
> 
> > +  tree bind_expr =
> > +    build3 (BIND_EXPR, void_type_node, NULL, stmt_list, block);
> 
> Operators go at the start of the line.

Fixed.

> > +  tree fn_type = build_function_type_array (integer_type_node, /*
> > return_type */
> 
> The line is too long, and we don't do /* arg name */ anyway.

Fixed.


> > +static void
> > +assert_loceq (const char *exp_filename,
> > +	      int exp_linenum,
> > +	      int exp_colnum,
> > +	      location_t loc)
> 
> > +static layout_range
> > +make_range (int start_line, int start_col,
> > +	    int end_line, int end_col)
> 
> These lines are too short :) Could save some vertical space here.

Fixed.


> For the future - I found the single merged patch easier to deal with 
> than the 16- or 21-patch series. Split ups are often good when
> modifying 
> the same code in multiple logically independent steps (keeping in
> mind 
> that bugfixes to newly added code shouldn't be split out either).
> This 
> is a different situation where the patches weren't truly independent,
> and the merged patch is essentially just a concatenation, so
> splitting 
> it up does not really make the review any easier (potentially harder
> if 
> you have to switch between mails rather than just hitting PgUp/Dn.

OK.  Sorry about that.

I'm testing a revised patch now, incorporating the above, and renaming
s-selftests (plural) to s-selftest (singular) etc within
gcc/Makefile.in as requested by Bernhard elsewhere in this thread.  I
assume that change is OK?

Thanks

Dave

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH] Selftest framework (v7)
  2016-06-06 14:17                                         ` David Malcolm
@ 2016-06-06 14:41                                           ` Bernd Schmidt
  2016-06-06 17:18                                             ` [Committed] Selftest framework (v8) David Malcolm
  2016-06-06 21:47                                           ` [PATCH] Selftest framework (v7) Trevor Saunders
  1 sibling, 1 reply; 176+ messages in thread
From: Bernd Schmidt @ 2016-06-06 14:41 UTC (permalink / raw)
  To: David Malcolm, Bernd Schmidt, gcc-patches; +Cc: Jeff Law

On 06/06/2016 04:17 PM, David Malcolm wrote:
> I'm testing a revised patch now, incorporating the above, and renaming
> s-selftests (plural) to s-selftest (singular) etc within
> gcc/Makefile.in as requested by Bernhard elsewhere in this thread.  I
> assume that change is OK?

Sure.


Bernd

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [Committed] Selftest framework (v8)
  2016-06-06 14:41                                           ` Bernd Schmidt
@ 2016-06-06 17:18                                             ` David Malcolm
  0 siblings, 0 replies; 176+ messages in thread
From: David Malcolm @ 2016-06-06 17:18 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches; +Cc: Jeff Law, David Malcolm

On Mon, 2016-06-06 at 16:40 +0200, Bernd Schmidt wrote:
> On 06/06/2016 04:17 PM, David Malcolm wrote:
> > I'm testing a revised patch now, incorporating the above, and
> > renaming
> > s-selftests (plural) to s-selftest (singular) etc within
> > gcc/Makefile.in as requested by Bernhard elsewhere in this thread. 
> >  I
> > assume that change is OK?
> 
> Sure.

Thanks.  I've committed v8 of the patch to trunk as r237144 (having
verified bootstrap&regtest on x86_64-pc-linux-gnu).

For reference, here's what I committed.

gcc/ChangeLog:
	* Makefile.in (OBJS): Add function-tests.o,
	hash-map-tests.o, hash-set-tests.o, rtl-tests.o,
	selftest-run-tests.o.
	(OBJS-libcommon): Add selftest.o.
	(OBJS-libcommon-target): Add selftest.o.
	(all.internal): Add "selftest".
	(all.cross): Likewise.
	(selftest): New phony target.
	(s-selftest): New target.
	(selftest-gdb): New phony target.
	(COLLECT2_OBJS): Add selftest.o.
	* bitmap.c: Include "selftest.h".
	(selftest::test_gc_alloc): New function.
	(selftest::test_set_range): New function.
	(selftest::test_clear_bit_in_middle): New function.
	(selftest::test_copying): New function.
	(selftest::test_bitmap_single_bit_set_p): New function.
	(selftest::bitmap_c_tests): New function.
	* common.opt (fself-test): New.
	* diagnostic-show-locus.c: Include "selftest.h".
	(make_range): New function.
	(test_range_contains_point_for_single_point): New function.
	(test_range_contains_point_for_single_line): New function.
	(test_range_contains_point_for_multiple_lines): New function.
	(assert_eq): New function.
	(test_get_line_width_without_trailing_whitespace): New function.
	(selftest::diagnostic_show_locus_c_tests): New function.
	* et-forest.c: Include "selftest.h".
	(selftest::test_single_node): New function.
	(selftest::test_simple_tree): New function.
	(selftest::test_disconnected_nodes): New function.
	(selftest::et_forest_c_tests): New function.
	* fold-const.c: Include "selftest.h".
	(selftest::assert_binop_folds_to_const): New function.
	(selftest::assert_binop_folds_to_nonlvalue): New function.
	(selftest::test_arithmetic_folding): New function.
	(selftest::fold_const_c_tests): New function.
	* function-tests.c: New file.
	* gimple.c: Include "selftest.h".
	Include "gimple-pretty-print.h".
	(selftest::verify_gimple_pp): New function.
	(selftest::test_assign_single): New function.
	(selftest::test_assign_binop): New function.
	(selftest::test_nop_stmt): New function.
	(selftest::test_return_stmt): New function.
	(selftest::test_return_without_value): New function.
	(selftest::gimple_c_tests): New function.
	* hash-map-tests.c: New file.
	* hash-set-tests.c: New file.
	* input.c: Include "selftest.h".
	(selftest::assert_loceq): New function.
	(selftest::test_accessing_ordinary_linemaps): New function.
	(selftest::test_unknown_location): New function.
	(selftest::test_builtins): New function.
	(selftest::test_reading_source_line): New function.
	(selftest::input_c_tests): New function.
	* rtl-tests.c: New file.
	* selftest-run-tests.c: New file.
	* selftest.c: New file.
	* selftest.h: New file.
	* spellcheck.c: Include "selftest.h".
	(selftest::levenshtein_distance_unit_test_oneway): New function,
	adapted from testsuite/gcc.dg/plugin/levenshtein_plugin.c.
	(selftest::levenshtein_distance_unit_test): Likewise.
	(selftest::spellcheck_c_tests): Likewise.
	* toplev.c: Include selftest.h.
	(toplev::run_self_tests): New.
	(toplev::main): Handle -fself-test.
	* toplev.h (toplev::run_self_tests): New.
	* tree.c: Include "selftest.h".
	(selftest::test_integer_constants): New function.
	(selftest::test_identifiers): New function.
	(selftest::test_labels): New function.
	(selftest::tree_c_tests): New function.
	* tree-cfg.c: Include "selftest.h".
	(selftest::push_fndecl): New function.
	(selftest::test_linear_chain): New function.
	(selftest::test_diamond): New function.
	(selftest::test_fully_connected): New function.
	(selftest::tree_cfg_c_tests): New function.
	* vec.c: Include "selftest.h".
	(selftest::safe_push_range): New function.
	(selftest::test_quick_push): New function.
	(selftest::test_safe_push): New function.
	(selftest::test_truncate): New function.
	(selftest::test_safe_grow_cleared): New function.
	(selftest::test_pop): New function.
	(selftest::test_safe_insert): New function.
	(selftest::test_ordered_remove): New function.
	(selftest::test_unordered_remove): New function.
	(selftest::test_block_remove): New function.
	(selftest::reverse_cmp): New function.
	(selftest::test_qsort): New function.
	(selftest::vec_c_tests): New function.c.
	* wide-int.cc: Include selftest.h and wide-int-print.h.
	(selftest::from_int <wide_int>): New function.
	(selftest::from_int <offset_int>): New function.
	(selftest::from_int <widest_int>): New function.
	(selftest::assert_deceq): New function.
	(selftest::assert_hexeq): New function.
	(selftest::test_printing <VALUE_TYPE>): New function template.
	(selftest::test_ops <VALUE_TYPE>): New function template.
	(selftest::test_comparisons <VALUE_TYPE>): New function template.
	(selftest::run_all_wide_int_tests <VALUE_TYPE>): New function
	template.
	(selftest::wide_int_cc_tests): New function.

gcc/testsuite/ChangeLog:
	* gcc.dg/plugin/levenshtein-test-1.c: Delete.
	* gcc.dg/plugin/levenshtein_plugin.c: Delete.
	* gcc.dg/plugin/plugin.exp (plugin_test_list): Remove the
	above.
---
 gcc/Makefile.in                                  |  31 +-
 gcc/bitmap.c                                     | 113 ++++
 gcc/common.opt                                   |   4 +
 gcc/diagnostic-show-locus.c                      | 166 ++++++
 gcc/et-forest.c                                  | 118 ++++
 gcc/fold-const.c                                 |  80 +++
 gcc/function-tests.c                             | 658 +++++++++++++++++++++++
 gcc/gimple.c                                     | 137 +++++
 gcc/hash-map-tests.c                             |  93 ++++
 gcc/hash-set-tests.c                             |  69 +++
 gcc/input.c                                      | 116 ++++
 gcc/rtl-tests.c                                  | 117 ++++
 gcc/selftest-run-tests.c                         |  77 +++
 gcc/selftest.c                                   |  47 ++
 gcc/selftest.h                                   | 153 ++++++
 gcc/spellcheck.c                                 |  58 ++
 gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c |   9 -
 gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c |  64 ---
 gcc/testsuite/gcc.dg/plugin/plugin.exp           |   1 -
 gcc/toplev.c                                     |  26 +
 gcc/toplev.h                                     |   2 +
 gcc/tree-cfg.c                                   | 278 ++++++++++
 gcc/tree.c                                       |  62 +++
 gcc/vec.c                                        | 192 +++++++
 gcc/wide-int.cc                                  | 170 ++++++
 25 files changed, 2762 insertions(+), 79 deletions(-)
 create mode 100644 gcc/function-tests.c
 create mode 100644 gcc/hash-map-tests.c
 create mode 100644 gcc/hash-set-tests.c
 create mode 100644 gcc/rtl-tests.c
 create mode 100644 gcc/selftest-run-tests.c
 create mode 100644 gcc/selftest.c
 create mode 100644 gcc/selftest.h
 delete mode 100644 gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c
 delete mode 100644 gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 2d6f1e8..fdcc42a 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1264,6 +1264,7 @@ OBJS = \
 	fold-const.o \
 	fold-const-call.o \
 	function.o \
+	function-tests.o \
 	fwprop.o \
 	gcc-rich-location.o \
 	gcse.o \
@@ -1299,6 +1300,8 @@ OBJS = \
 	graphite-sese-to-poly.o \
 	gtype-desc.o \
 	haifa-sched.o \
+	hash-map-tests.o \
+	hash-set-tests.o \
 	hsa.o \
 	hsa-gen.o \
 	hsa-regalloc.o \
@@ -1399,6 +1402,7 @@ OBJS = \
 	resource.o \
 	rtl-chkp.o \
 	rtl-error.o \
+	rtl-tests.o \
 	rtl.o \
 	rtlhash.o \
 	rtlanal.o \
@@ -1411,6 +1415,7 @@ OBJS = \
 	sel-sched-ir.o \
 	sel-sched-dump.o \
 	sel-sched.o \
+	selftest-run-tests.o \
 	sese.o \
 	shrink-wrap.o \
 	simplify-rtx.o \
@@ -1543,13 +1548,14 @@ OBJS = \
 # no target dependencies.
 OBJS-libcommon = diagnostic.o diagnostic-color.o diagnostic-show-locus.o \
 	pretty-print.o intl.o \
-	vec.o input.o version.o hash-table.o ggc-none.o memory-block.o
+	vec.o input.o version.o hash-table.o ggc-none.o memory-block.o \
+	selftest.o
 
 # Objects in libcommon-target.a, used by drivers and by the core
 # compiler and containing target-dependent code.
 OBJS-libcommon-target = $(common_out_object_file) prefix.o params.o \
 	opts.o opts-common.o options.o vec.o hooks.o common/common-targhooks.o \
-	hash-table.o file-find.o spellcheck.o
+	hash-table.o file-find.o spellcheck.o selftest.o
 
 # This lists all host objects for the front ends.
 ALL_HOST_FRONTEND_OBJS = $(foreach v,$(CONFIG_LANGUAGES),$($(v)_OBJS))
@@ -1816,10 +1822,10 @@ config.status: $(srcdir)/configure $(srcdir)/config.gcc
 quickstrap: all
 	cd $(toplevel_builddir) && $(MAKE) all-target-libgcc
 
-all.internal: start.encap rest.encap doc
+all.internal: start.encap rest.encap doc selftest
 # This is what to compile if making a cross-compiler.
 all.cross: native gcc-cross$(exeext) cpp$(exeext) specs \
-	libgcc-support lang.all.cross doc @GENINSRC@ srcextra
+	libgcc-support lang.all.cross doc selftest @GENINSRC@ srcextra
 # This is what must be made before installing GCC and converting libraries.
 start.encap: native xgcc$(exeext) cpp$(exeext) specs \
 	libgcc-support lang.start.encap @GENINSRC@ srcextra
@@ -1839,6 +1845,21 @@ endif
 # This does the things that can't be done on the host machine.
 rest.cross: specs
 
+# Run the selftests during the build once we have a driver and a cc1,
+# so that self-test failures are caught as early as possible.
+# Use "s-selftest" to ensure that we only run the selftests if the
+# driver or cc1 change.
+.PHONY: selftest
+selftest: s-selftest
+s-selftest: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs
+	$(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test
+	$(STAMP) $@
+
+# Convenience method for running selftests under gdb:
+.PHONY: selftest-gdb
+selftest-gdb: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs
+	$(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test -wrapper gdb,--args
+
 # Recompile all the language-independent object files.
 # This is used only if the user explicitly asks for it.
 compilations: $(BACKEND)
@@ -1986,7 +2007,7 @@ gcc-nm.c: gcc-ar.c
 	cp $^ $@
 
 COLLECT2_OBJS = collect2.o collect2-aix.o tlink.o vec.o ggc-none.o \
-  collect-utils.o file-find.o hash-table.o
+  collect-utils.o file-find.o hash-table.o selftest.o
 COLLECT2_LIBS = @COLLECT2_LIBS@
 collect2$(exeext): $(COLLECT2_OBJS) $(LIBDEPS)
 # Don't try modifying collect2 (aka ld) in place--it might be linking this.
diff --git a/gcc/bitmap.c b/gcc/bitmap.c
index 010cf75..6206535 100644
--- a/gcc/bitmap.c
+++ b/gcc/bitmap.c
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "bitmap.h"
+#include "selftest.h"
 
 /* Memory allocation statistics purpose instance.  */
 mem_alloc_description<bitmap_usage> bitmap_mem_desc;
@@ -2162,5 +2163,117 @@ debug (const bitmap_head *ptr)
     fprintf (stderr, "<nil>\n");
 }
 
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests for bitmaps.  */
+
+/* Freshly-created bitmaps ought to be empty.  */
+
+static void
+test_gc_alloc ()
+{
+  bitmap b = bitmap_gc_alloc ();
+  ASSERT_TRUE (bitmap_empty_p (b));
+}
+
+/* Verify bitmap_set_range.  */
+
+static void
+test_set_range ()
+{
+  bitmap b = bitmap_gc_alloc ();
+  ASSERT_TRUE (bitmap_empty_p (b));
+
+  bitmap_set_range (b, 7, 5);
+  ASSERT_FALSE (bitmap_empty_p (b));
+  ASSERT_EQ (5, bitmap_count_bits (b));
+
+  /* Verify bitmap_bit_p at the boundaries.  */
+  ASSERT_FALSE (bitmap_bit_p (b, 6));
+  ASSERT_TRUE (bitmap_bit_p (b, 7));
+  ASSERT_TRUE (bitmap_bit_p (b, 11));
+  ASSERT_FALSE (bitmap_bit_p (b, 12));
+}
+
+/* Verify splitting a range into two pieces using bitmap_clear_bit.  */
+
+static void
+test_clear_bit_in_middle ()
+{
+  bitmap b = bitmap_gc_alloc ();
+
+  /* Set b to [100..200].  */
+  bitmap_set_range (b, 100, 100);
+  ASSERT_EQ (100, bitmap_count_bits (b));
+
+  /* Clear a bit in the middle.  */
+  bool changed = bitmap_clear_bit (b, 150);
+  ASSERT_TRUE (changed);
+  ASSERT_EQ (99, bitmap_count_bits (b));
+  ASSERT_TRUE (bitmap_bit_p (b, 149));
+  ASSERT_FALSE (bitmap_bit_p (b, 150));
+  ASSERT_TRUE (bitmap_bit_p (b, 151));
+}
+
+/* Verify bitmap_copy.  */
+
+static void
+test_copying ()
+{
+  bitmap src = bitmap_gc_alloc ();
+  bitmap_set_range (src, 40, 10);
+
+  bitmap dst = bitmap_gc_alloc ();
+  ASSERT_FALSE (bitmap_equal_p (src, dst));
+  bitmap_copy (dst, src);
+  ASSERT_TRUE (bitmap_equal_p (src, dst));
+
+  /* Verify that we can make them unequal again...  */
+  bitmap_set_range (src, 70, 5);
+  ASSERT_FALSE (bitmap_equal_p (src, dst));
+
+  /* ...and that changing src after the copy didn't affect
+     the other: */
+  ASSERT_FALSE (bitmap_bit_p (dst, 70));
+}
+
+/* Verify bitmap_single_bit_set_p.  */
+
+static void
+test_bitmap_single_bit_set_p ()
+{
+  bitmap b = bitmap_gc_alloc ();
+
+  ASSERT_FALSE (bitmap_single_bit_set_p (b));
+
+  bitmap_set_range (b, 42, 1);
+  ASSERT_TRUE (bitmap_single_bit_set_p (b));
+  ASSERT_EQ (42, bitmap_first_set_bit (b));
+
+  bitmap_set_range (b, 1066, 1);
+  ASSERT_FALSE (bitmap_single_bit_set_p (b));
+  ASSERT_EQ (42, bitmap_first_set_bit (b));
+
+  bitmap_clear_range (b, 0, 100);
+  ASSERT_TRUE (bitmap_single_bit_set_p (b));
+  ASSERT_EQ (1066, bitmap_first_set_bit (b));
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+bitmap_c_tests ()
+{
+  test_gc_alloc ();
+  test_set_range ();
+  test_clear_bit_in_middle ();
+  test_copying ();
+  test_bitmap_single_bit_set_p ();
+}
+
+} // namespace selftest
+#endif /* CHECKING_P */
 
 #include "gt-bitmap.h"
diff --git a/gcc/common.opt b/gcc/common.opt
index 2bb576c..632dd31 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2066,6 +2066,10 @@ fselective-scheduling2
 Common Report Var(flag_selective_scheduling2) Optimization
 Run selective scheduling after reload.
 
+fself-test
+Common Undocumented Var(flag_self_test)
+Run self-tests.
+
 fsel-sched-pipelining
 Common Report Var(flag_sel_sched_pipelining) Init(0) Optimization
 Perform software pipelining of inner loops during selective scheduling.
diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
index eeccee5..7aab658 100644
--- a/gcc/diagnostic-show-locus.c
+++ b/gcc/diagnostic-show-locus.c
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "backtrace.h"
 #include "diagnostic.h"
 #include "diagnostic-color.h"
+#include "selftest.h"
 
 #ifdef HAVE_TERMIOS_H
 # include <termios.h>
@@ -442,6 +443,123 @@ layout_range::contains_point (int row, int column) const
   return column <= m_finish.m_column;
 }
 
+#if CHECKING_P
+
+/* A helper function for testing layout_range::contains_point.  */
+
+static layout_range
+make_range (int start_line, int start_col, int end_line, int end_col)
+{
+  const expanded_location start_exploc
+    = {"test.c", start_line, start_col, NULL, false};
+  const expanded_location finish_exploc
+    = {"test.c", end_line, end_col, NULL, false};
+  return layout_range (&start_exploc, &finish_exploc, false,
+		       &start_exploc);
+}
+
+/* Selftests for layout_range::contains_point.  */
+
+/* Selftest for layout_range::contains_point where the layout_range
+   is a range with start==end i.e. a single point.  */
+
+static void
+test_range_contains_point_for_single_point ()
+{
+  layout_range point = make_range (7, 10, 7, 10);
+
+  /* Before the line. */
+  ASSERT_FALSE (point.contains_point (6, 1));
+
+  /* On the line, but before start.  */
+  ASSERT_FALSE (point.contains_point (7, 9));
+
+  /* At the point.  */
+  ASSERT_TRUE (point.contains_point (7, 10));
+
+  /* On the line, after the point.  */
+  ASSERT_FALSE (point.contains_point (7, 11));
+
+  /* After the line.  */
+  ASSERT_FALSE (point.contains_point (8, 1));
+}
+
+/* Selftest for layout_range::contains_point where the layout_range
+   is the single-line range shown as "Example A" above.  */
+
+static void
+test_range_contains_point_for_single_line ()
+{
+  layout_range example_a = make_range (2, 22, 2, 38);
+
+  /* Before the line. */
+  ASSERT_FALSE (example_a.contains_point (1, 1));
+
+  /* On the line, but before start.  */
+  ASSERT_FALSE (example_a.contains_point (2, 21));
+
+  /* On the line, at the start.  */
+  ASSERT_TRUE (example_a.contains_point (2, 22));
+
+  /* On the line, within the range.  */
+  ASSERT_TRUE (example_a.contains_point (2, 23));
+
+  /* On the line, at the end.  */
+  ASSERT_TRUE (example_a.contains_point (2, 38));
+
+  /* On the line, after the end.  */
+  ASSERT_FALSE (example_a.contains_point (2, 39));
+
+  /* After the line.  */
+  ASSERT_FALSE (example_a.contains_point (2, 39));
+}
+
+/* Selftest for layout_range::contains_point where the layout_range
+   is the multi-line range shown as "Example B" above.  */
+
+static void
+test_range_contains_point_for_multiple_lines ()
+{
+  layout_range example_b = make_range (3, 14, 5, 8);
+
+  /* Before first line. */
+  ASSERT_FALSE (example_b.contains_point (1, 1));
+
+  /* On the first line, but before start.  */
+  ASSERT_FALSE (example_b.contains_point (3, 13));
+
+  /* At the start.  */
+  ASSERT_TRUE (example_b.contains_point (3, 14));
+
+  /* On the first line, within the range.  */
+  ASSERT_TRUE (example_b.contains_point (3, 15));
+
+  /* On an interior line.
+     The column number should not matter; try various boundary
+     values.  */
+  ASSERT_TRUE (example_b.contains_point (4, 1));
+  ASSERT_TRUE (example_b.contains_point (4, 7));
+  ASSERT_TRUE (example_b.contains_point (4, 8));
+  ASSERT_TRUE (example_b.contains_point (4, 9));
+  ASSERT_TRUE (example_b.contains_point (4, 13));
+  ASSERT_TRUE (example_b.contains_point (4, 14));
+  ASSERT_TRUE (example_b.contains_point (4, 15));
+
+  /* On the final line, before the end.  */
+  ASSERT_TRUE (example_b.contains_point (5, 7));
+
+  /* On the final line, at the end.  */
+  ASSERT_TRUE (example_b.contains_point (5, 8));
+
+  /* On the final line, after the end.  */
+  ASSERT_FALSE (example_b.contains_point (5, 9));
+
+  /* After the line.  */
+  ASSERT_FALSE (example_b.contains_point (6, 1));
+}
+
+#endif /* #if CHECKING_P */
+
 /* Given a source line LINE of length LINE_WIDTH, determine the width
    without any trailing whitespace.  */
 
@@ -465,6 +583,34 @@ get_line_width_without_trailing_whitespace (const char *line, int line_width)
   return result;
 }
 
+#if CHECKING_P
+
+/* A helper function for testing get_line_width_without_trailing_whitespace.  */
+
+static void
+assert_eq (const char *line, int expected_width)
+{
+  int actual_value
+    = get_line_width_without_trailing_whitespace (line, strlen (line));
+  ASSERT_EQ (actual_value, expected_width);
+}
+
+/* Verify that get_line_width_without_trailing_whitespace is sane for
+   various inputs.  It is not required to handle newlines.  */
+
+static void
+test_get_line_width_without_trailing_whitespace ()
+{
+  assert_eq ("", 0);
+  assert_eq (" ", 0);
+  assert_eq ("\t", 0);
+  assert_eq ("hello world", 11);
+  assert_eq ("hello world     ", 11);
+  assert_eq ("hello world     \t\t  ", 11);
+}
+
+#endif /* #if CHECKING_P */
+
 /* Helper function for layout's ctor, for sanitizing locations relative
    to the primary location within a diagnostic.
 
@@ -1171,3 +1317,23 @@ diagnostic_show_locus (diagnostic_context * context,
 
   pp_set_prefix (context->printer, saved_prefix);
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Run all of the selftests within this file.  */
+
+void
+diagnostic_show_locus_c_tests ()
+{
+  test_range_contains_point_for_single_point ();
+  test_range_contains_point_for_single_line ();
+  test_range_contains_point_for_multiple_lines ();
+
+  test_get_line_width_without_trailing_whitespace ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/et-forest.c b/gcc/et-forest.c
index cd36752..766a1a3 100644
--- a/gcc/et-forest.c
+++ b/gcc/et-forest.c
@@ -27,6 +27,7 @@ License along with libiberty; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "alloc-pool.h"
 #include "et-forest.h"
+#include "selftest.h"
 
 /* We do not enable this with CHECKING_P, since it is awfully slow.  */
 #undef DEBUG_ET
@@ -764,3 +765,120 @@ et_root (struct et_node *node)
 
   return r->of;
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests for et-forest.c.  */
+
+/* Perform sanity checks for a tree consisting of a single node.  */
+
+static void
+test_single_node ()
+{
+  void *test_data = (void *)0xcafebabe;
+
+  et_node *n = et_new_tree (test_data);
+  ASSERT_EQ (n->data, test_data);
+  ASSERT_EQ (n, et_root (n));
+  et_free_tree (n);
+}
+
+/* Test of this tree:
+       a
+      / \
+     /   \
+    b     c
+   / \    |
+  d   e   f.  */
+
+static void
+test_simple_tree ()
+{
+  et_node *a = et_new_tree (NULL);
+  et_node *b = et_new_tree (NULL);
+  et_node *c = et_new_tree (NULL);
+  et_node *d = et_new_tree (NULL);
+  et_node *e = et_new_tree (NULL);
+  et_node *f = et_new_tree (NULL);
+
+  et_set_father (b, a);
+  et_set_father (c, a);
+  et_set_father (d, b);
+  et_set_father (e, b);
+  et_set_father (f, c);
+
+  ASSERT_TRUE (et_below (a, a));
+  ASSERT_TRUE (et_below (b, a));
+  ASSERT_TRUE (et_below (c, a));
+  ASSERT_TRUE (et_below (d, a));
+  ASSERT_TRUE (et_below (e, a));
+  ASSERT_TRUE (et_below (f, a));
+
+  ASSERT_FALSE (et_below (a, b));
+  ASSERT_TRUE (et_below (b, b));
+  ASSERT_FALSE (et_below (c, b));
+  ASSERT_TRUE (et_below (d, b));
+  ASSERT_TRUE (et_below (e, b));
+  ASSERT_FALSE (et_below (f, b));
+
+  ASSERT_FALSE (et_below (a, c));
+  ASSERT_FALSE (et_below (b, c));
+  ASSERT_TRUE (et_below (c, c));
+  ASSERT_FALSE (et_below (d, c));
+  ASSERT_FALSE (et_below (e, c));
+  ASSERT_TRUE (et_below (f, c));
+
+  ASSERT_FALSE (et_below (a, d));
+  ASSERT_FALSE (et_below (b, d));
+  ASSERT_FALSE (et_below (c, d));
+  ASSERT_TRUE (et_below (d, d));
+  ASSERT_FALSE (et_below (e, d));
+  ASSERT_FALSE (et_below (f, d));
+
+  ASSERT_FALSE (et_below (a, e));
+  ASSERT_FALSE (et_below (b, e));
+  ASSERT_FALSE (et_below (c, e));
+  ASSERT_FALSE (et_below (d, e));
+  ASSERT_TRUE (et_below (e, e));
+  ASSERT_FALSE (et_below (f, e));
+
+  ASSERT_FALSE (et_below (a, f));
+  ASSERT_FALSE (et_below (b, f));
+  ASSERT_FALSE (et_below (c, f));
+  ASSERT_FALSE (et_below (d, f));
+  ASSERT_FALSE (et_below (e, f));
+  ASSERT_TRUE (et_below (f, f));
+
+  et_free_tree_force (a);
+}
+
+/* Verify that two disconnected nodes are unrelated.  */
+
+static void
+test_disconnected_nodes ()
+{
+  et_node *a = et_new_tree (NULL);
+  et_node *b = et_new_tree (NULL);
+
+  ASSERT_FALSE (et_below (a, b));
+  ASSERT_FALSE (et_below (b, a));
+
+  et_free_tree (a);
+  et_free_tree (b);
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+et_forest_c_tests ()
+{
+  test_single_node ();
+  test_simple_tree ();
+  test_disconnected_nodes ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 5058746..0efa9d5 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -76,6 +76,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "case-cfn-macros.h"
 #include "stringpool.h"
 #include "tree-ssanames.h"
+#include "selftest.h"
 
 #ifndef LOAD_EXTEND_OP
 #define LOAD_EXTEND_OP(M) UNKNOWN
@@ -14496,3 +14497,82 @@ c_getstr (tree src)
 
   return TREE_STRING_POINTER (src) + tree_to_uhwi (offset_node);
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Helper functions for writing tests of folding trees.  */
+
+/* Verify that the binary op (LHS CODE RHS) folds to CONSTANT.  */
+
+static void
+assert_binop_folds_to_const (tree lhs, enum tree_code code, tree rhs,
+			     tree constant)
+{
+  ASSERT_EQ (constant, fold_build2 (code, TREE_TYPE (lhs), lhs, rhs));
+}
+
+/* Verify that the binary op (LHS CODE RHS) folds to an NON_LVALUE_EXPR
+   wrapping WRAPPED_EXPR.  */
+
+static void
+assert_binop_folds_to_nonlvalue (tree lhs, enum tree_code code, tree rhs,
+				 tree wrapped_expr)
+{
+  tree result = fold_build2 (code, TREE_TYPE (lhs), lhs, rhs);
+  ASSERT_NE (wrapped_expr, result);
+  ASSERT_EQ (NON_LVALUE_EXPR, TREE_CODE (result));
+  ASSERT_EQ (wrapped_expr, TREE_OPERAND (result, 0));
+}
+
+/* Verify that various arithmetic binary operations are folded
+   correctly.  */
+
+static void
+test_arithmetic_folding ()
+{
+  tree type = integer_type_node;
+  tree x = create_tmp_var_raw (type, "x");
+  tree zero = build_zero_cst (type);
+  tree one = build_int_cst (type, 1);
+
+  /* Addition.  */
+  /* 1 <-- (0 + 1) */
+  assert_binop_folds_to_const (zero, PLUS_EXPR, one,
+			       one);
+  assert_binop_folds_to_const (one, PLUS_EXPR, zero,
+			       one);
+
+  /* (nonlvalue)x <-- (x + 0) */
+  assert_binop_folds_to_nonlvalue (x, PLUS_EXPR, zero,
+				   x);
+
+  /* Subtraction.  */
+  /* 0 <-- (x - x) */
+  assert_binop_folds_to_const (x, MINUS_EXPR, x,
+			       zero);
+  assert_binop_folds_to_nonlvalue (x, MINUS_EXPR, zero,
+				   x);
+
+  /* Multiplication.  */
+  /* 0 <-- (x * 0) */
+  assert_binop_folds_to_const (x, MULT_EXPR, zero,
+			       zero);
+
+  /* (nonlvalue)x <-- (x * 1) */
+  assert_binop_folds_to_nonlvalue (x, MULT_EXPR, one,
+				   x);
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+fold_const_c_tests ()
+{
+  test_arithmetic_folding ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
diff --git a/gcc/function-tests.c b/gcc/function-tests.c
new file mode 100644
index 0000000..c8188e7
--- /dev/null
+++ b/gcc/function-tests.c
@@ -0,0 +1,658 @@
+/* Unit tests for function-handling.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "hard-reg-set.h"
+#include "input.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "gimple-expr.h"
+#include "toplev.h"
+#include "print-tree.h"
+#include "tree-iterator.h"
+#include "gimplify.h"
+#include "tree-cfg.h"
+#include "basic-block.h"
+#include "double-int.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "stmt.h"
+#include "hash-table.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "context.h"
+#include "hash-map.h"
+#include "plugin-api.h"
+#include "ipa-ref.h"
+#include "cgraph.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Helper function for selftests of function-creation.  */
+
+static tree
+make_fndecl (tree return_type,
+	     const char *name,
+	     vec <tree> &param_types,
+	     bool is_variadic = false)
+{
+  tree fn_type;
+  if (is_variadic)
+    fn_type = build_varargs_function_type_array (return_type,
+						 param_types.length (),
+						 param_types.address ());
+  else
+    fn_type = build_function_type_array (return_type,
+					 param_types.length (),
+					 param_types.address ());
+  /* FIXME: this uses input_location: */
+  tree fndecl = build_fn_decl (name, fn_type);
+
+  return fndecl;
+}
+
+/* Verify creating a function declaration equivalent to the following
+     int test_fndecl_int_void (void);
+   C declaration.  */
+
+static void
+test_fndecl_int_void ()
+{
+  auto_vec <tree> param_types;
+  const char *name = "test_fndecl_int_void";
+  tree fndecl = make_fndecl (integer_type_node,
+			     name,
+			     param_types);
+  ASSERT_TRUE (fndecl != NULL);
+
+  /* Verify name of decl.  */
+  tree declname = DECL_NAME (fndecl);
+  ASSERT_TRUE (declname != NULL);
+  ASSERT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
+  /* We expect it to use a *copy* of the string we passed in.  */
+  const char *identifier_ptr = IDENTIFIER_POINTER (declname);
+  ASSERT_NE (name, identifier_ptr);
+  ASSERT_EQ (0, strcmp ("test_fndecl_int_void", identifier_ptr));
+
+  /* Verify type of fndecl.  */
+  ASSERT_EQ (FUNCTION_DECL, TREE_CODE (fndecl));
+  tree fntype = TREE_TYPE (fndecl);
+  ASSERT_EQ (FUNCTION_TYPE, TREE_CODE (fntype));
+
+  /* Verify return type.  */
+  ASSERT_EQ (integer_type_node, TREE_TYPE (fntype));
+
+  /* Verify "void" args.  */
+  tree argtypes = TYPE_ARG_TYPES (fntype);
+  ASSERT_EQ (TREE_LIST, TREE_CODE (argtypes));
+  ASSERT_EQ (void_type_node, TREE_VALUE (argtypes));
+  ASSERT_EQ (NULL, TREE_CHAIN (argtypes));
+}
+
+/* Verify creating a function declaration equivalent to the following
+     float test_fndecl_float_intchar (int, char);
+   C declaration.  */
+
+static void
+test_fndecl_float_intchar ()
+{
+  auto_vec <tree> param_types;
+  param_types.safe_push (integer_type_node);
+  param_types.safe_push (char_type_node);
+  const char *name = "test_fndecl_float_intchar";
+  tree fndecl = make_fndecl (float_type_node,
+			     name,
+			     param_types);
+  ASSERT_TRUE (fndecl != NULL);
+
+  /* Verify name of decl.  */
+  tree declname = DECL_NAME (fndecl);
+  ASSERT_TRUE (declname != NULL);
+  ASSERT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
+  /* We expect it to use a *copy* of the string we passed in.  */
+  const char *identifier_ptr = IDENTIFIER_POINTER (declname);
+  ASSERT_NE (name, identifier_ptr);
+  ASSERT_EQ (0, strcmp (name, identifier_ptr));
+
+  /* Verify type of fndecl.  */
+  ASSERT_EQ (FUNCTION_DECL, TREE_CODE (fndecl));
+  tree fntype = TREE_TYPE (fndecl);
+  ASSERT_EQ (FUNCTION_TYPE, TREE_CODE (fntype));
+
+  /* Verify return type.  */
+  ASSERT_EQ (float_type_node, TREE_TYPE (fntype));
+
+  /* Verify "(int, char)" args.  */
+  tree arg0 = TYPE_ARG_TYPES (fntype);
+  ASSERT_EQ (TREE_LIST, TREE_CODE (arg0));
+  ASSERT_EQ (integer_type_node, TREE_VALUE (arg0));
+  tree arg1 = TREE_CHAIN (arg0);
+  ASSERT_TRUE (arg1 != NULL);
+  ASSERT_EQ (TREE_LIST, TREE_CODE (arg1));
+  ASSERT_EQ (char_type_node, TREE_VALUE (arg1));
+  tree argterm = TREE_CHAIN (arg1);
+  ASSERT_TRUE (argterm != NULL);
+  ASSERT_EQ (TREE_LIST, TREE_CODE (argterm));
+  ASSERT_EQ (void_type_node, TREE_VALUE (argterm));
+  ASSERT_EQ (NULL, TREE_CHAIN (argterm));
+}
+
+/* The test cases using these helper functions take a trivial function:
+
+     int test_fn (void) { return 42; }
+
+   and test various conversions done to it:
+
+   - gimplification
+   - construction of the CFG
+   - conversion to SSA form
+   - expansion to RTL form
+
+   In avoid having one overlong test case, this is broken
+   up into separate test cases for each stage, with helper functions
+   to minimize code duplication.
+
+   Another approach would be to attempt to directly construct a function
+   in the appropriate representation at each stage, though presumably
+   that would exhibit different kinds of failure compared to this
+   approach.  */
+
+/* Construct this function:
+   int test_fn (void) { return 42; }
+   in generic tree form.  Return the fndecl.  */
+
+static tree
+build_trivial_generic_function ()
+{
+  auto_vec <tree> param_types;
+  tree fndecl = make_fndecl (integer_type_node,
+			     "test_fn",
+			     param_types);
+  ASSERT_TRUE (fndecl != NULL);
+
+  /* Populate the function.  */
+  tree retval = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+			    NULL_TREE, integer_type_node);
+  DECL_ARTIFICIAL (retval) = 1;
+  DECL_IGNORED_P (retval) = 1;
+  DECL_RESULT (fndecl) = retval;
+
+  /* Create a BIND_EXPR, and within it, a statement list.  */
+  tree stmt_list = alloc_stmt_list ();
+  tree_stmt_iterator stmt_iter = tsi_start (stmt_list);
+  tree block = make_node (BLOCK);
+  tree bind_expr
+    = build3 (BIND_EXPR, void_type_node, NULL, stmt_list, block);
+
+  tree modify_retval = build2 (MODIFY_EXPR,
+			       integer_type_node,
+			       retval,
+			       build_int_cst (integer_type_node, 42));
+  tree return_stmt = build1 (RETURN_EXPR,
+			     integer_type_node,
+			     modify_retval);
+  tsi_link_after (&stmt_iter, return_stmt, TSI_CONTINUE_LINKING);
+
+  DECL_INITIAL (fndecl) = block;
+
+  /* how to add to function? the following appears to be how to
+     set the body of a fndecl: */
+  DECL_SAVED_TREE(fndecl) = bind_expr;
+
+  /* Ensure that locals appear in the debuginfo.  */
+  BLOCK_VARS (block) = BIND_EXPR_VARS (bind_expr);
+
+  return fndecl;
+}
+
+/* Construct this function:
+     int test_fn (void) { return 42; }
+   in "high gimple" form.  Return the fndecl.  */
+
+static tree
+build_trivial_high_gimple_function ()
+{
+  /* Construct a trivial function, and gimplify it: */
+  tree fndecl = build_trivial_generic_function ();
+  gimplify_function_tree (fndecl);
+  return fndecl;
+}
+
+/* Build a CFG for a function in gimple form.  */
+
+static void
+build_cfg (tree fndecl)
+{
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  ASSERT_EQ (fndecl, fun->decl);
+
+  /* We first have to lower control flow; for our trivial test function
+     this gives us:
+	 test_fn ()
+	 {
+	   D.56 = 42;
+	   goto <D.57>;
+	   <D.57>:
+	   return D.56;
+	 }
+  */
+  gimple_opt_pass *lower_cf_pass = make_pass_lower_cf (g);
+  push_cfun (fun);
+  lower_cf_pass->execute (fun);
+  pop_cfun ();
+
+  /* We can now convert to CFG form; for our trivial test function this
+     gives us:
+	 test_fn ()
+	 {
+	   <bb 2>:
+	   D.56 = 42;
+	   return D.56;
+	 }
+  */
+  gimple_opt_pass *build_cfg_pass = make_pass_build_cfg (g);
+  push_cfun (fun);
+  build_cfg_pass->execute (fun);
+  pop_cfun ();
+}
+
+/* Convert a gimple+CFG function to SSA form.  */
+
+static void
+convert_to_ssa (tree fndecl)
+{
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  ASSERT_EQ (fndecl, fun->decl);
+
+  gimple_opt_pass *build_ssa_pass = make_pass_build_ssa (g);
+  push_cfun (fun);
+  build_ssa_pass->execute (fun);
+  pop_cfun ();
+}
+
+/* Assuming we have a simple 3-block CFG like this:
+     [ENTRY] -> [block2] -> [EXIT]
+   get the "real" basic block (block 2).  */
+
+static basic_block
+get_real_block (function *fun)
+{
+  ASSERT_TRUE (fun->cfg != NULL);
+  ASSERT_EQ (3, n_basic_blocks_for_fn (fun));
+  basic_block bb2 = (*fun->cfg->x_basic_block_info)[2];
+  ASSERT_TRUE (bb2 != NULL);
+  return bb2;
+}
+
+/* Verify that we have a simple 3-block CFG: the two "fake" ones, and
+   a "real" one:
+     [ENTRY] -> [block2] -> [EXIT].  */
+
+static void
+verify_three_block_cfg (function *fun)
+{
+  ASSERT_TRUE (fun->cfg != NULL);
+  ASSERT_EQ (3, n_basic_blocks_for_fn (fun));
+  ASSERT_EQ (2, n_edges_for_fn (fun));
+
+  /* The "fake" basic blocks.  */
+  basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (entry != NULL);
+  ASSERT_EQ (ENTRY_BLOCK, entry->index);
+
+  basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (exit != NULL);
+  ASSERT_EQ (EXIT_BLOCK, exit->index);
+
+  /* The "real" basic block.  */
+  basic_block bb2 = get_real_block (fun);
+  ASSERT_TRUE (bb2 != NULL);
+  ASSERT_EQ (2, bb2->index);
+
+  /* Verify connectivity.  */
+  ASSERT_EQ (NULL, entry->preds);
+  ASSERT_EQ (1, entry->succs->length ());
+
+  edge from_entry_to_bb2 = (*entry->succs)[0];
+  ASSERT_EQ (entry, from_entry_to_bb2->src);
+  ASSERT_EQ (bb2, from_entry_to_bb2->dest);
+
+  ASSERT_EQ (1, bb2->preds->length ());
+  ASSERT_EQ (from_entry_to_bb2, (*bb2->preds)[0]);
+  ASSERT_EQ (1, bb2->succs->length ());
+
+  edge from_bb2_to_exit = (*bb2->succs)[0];
+  ASSERT_EQ (bb2, from_bb2_to_exit->src);
+  ASSERT_EQ (exit, from_bb2_to_exit->dest);
+
+  ASSERT_EQ (1, exit->preds->length ());
+  ASSERT_EQ (from_bb2_to_exit, (*exit->preds)[0]);
+  ASSERT_EQ (NULL, exit->succs);
+}
+
+/* As above, but additionally verify the gimple statements are sane.  */
+
+static void
+verify_three_block_gimple_cfg (function *fun)
+{
+  verify_three_block_cfg (fun);
+
+  /* The "fake" basic blocks should be flagged as gimple, but with have no
+     statements.  */
+  basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (entry != NULL);
+  ASSERT_EQ (0, entry->flags & BB_RTL);
+  ASSERT_EQ (NULL, bb_seq (entry));
+
+  basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (exit != NULL);
+  ASSERT_EQ (0, entry->flags & BB_RTL);
+  ASSERT_EQ (NULL, bb_seq (exit));
+
+  /* The "real" basic block should be flagged as gimple, and have one
+     or more statements.  */
+  basic_block bb2 = get_real_block (fun);
+  ASSERT_TRUE (bb2 != NULL);
+  ASSERT_EQ (0, entry->flags & BB_RTL);
+  ASSERT_TRUE (bb_seq (bb2) != NULL);
+}
+
+/* As above, but additionally verify the RTL insns are sane.  */
+
+static void
+verify_three_block_rtl_cfg (function *fun)
+{
+  verify_three_block_cfg (fun);
+
+  /* The "fake" basic blocks should be flagged as RTL, but with no
+     insns.  */
+  basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (entry != NULL);
+  ASSERT_EQ (BB_RTL, entry->flags & BB_RTL);
+  ASSERT_EQ (NULL, BB_HEAD (entry));
+
+  basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (exit != NULL);
+  ASSERT_EQ (BB_RTL, entry->flags & BB_RTL);
+  ASSERT_EQ (NULL, BB_HEAD (exit));
+
+  /* The "real" basic block should be flagged as RTL, and have one
+     or more insns.  */
+  basic_block bb2 = get_real_block (fun);
+  ASSERT_TRUE (bb2 != NULL);
+  ASSERT_EQ (BB_RTL, entry->flags & BB_RTL);
+  ASSERT_TRUE (BB_HEAD (bb2) != NULL);
+}
+
+/* Test converting our trivial function:
+     int test_fn (void) { return 42; }
+   to gimple form.  */
+
+static void
+test_gimplification ()
+{
+  tree fndecl = build_trivial_generic_function ();
+
+  /* Convert to gimple: */
+  gimplify_function_tree (fndecl);
+
+  /* Verify that we got gimple out of it.  */
+
+  /* The function is now in GIMPLE form but the CFG has not been
+     built yet.  */
+
+  /* We should have a struct function for the decl.  */
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  ASSERT_EQ (fndecl, fun->decl);
+
+  /* We expect a GIMPLE_BIND, with two gimple statements within it:
+       tmp = 42;
+       return tmp;  */
+
+  gimple_seq seq_fn_body = gimple_body (fndecl);
+  ASSERT_TRUE (seq_fn_body != NULL);
+  gimple *bind_stmt = gimple_seq_first_stmt (seq_fn_body);
+  ASSERT_EQ (GIMPLE_BIND, gimple_code (bind_stmt));
+  ASSERT_EQ (NULL, bind_stmt->next);
+
+  gimple_seq seq_bind_body = gimple_bind_body (as_a <gbind *> (bind_stmt));
+
+  /* Verify that we have the 2 statements we expect.  */
+  ASSERT_TRUE (seq_bind_body != NULL);
+  gimple *stmt1 = gimple_seq_first_stmt (seq_bind_body);
+  ASSERT_TRUE (stmt1 != NULL);
+  ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt1));
+  gimple *stmt2 = stmt1->next;
+  ASSERT_TRUE (stmt2 != NULL);
+  ASSERT_EQ (stmt1, stmt2->prev);
+  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt2));
+}
+
+/* Test of building a CFG for a function in high gimple form.  */
+
+static void
+test_building_cfg ()
+{
+  /* Construct a trivial function, and gimplify it: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+
+  /* Build a CFG.  */
+  build_cfg (fndecl);
+
+  /* The CFG-building code constructs a 4-block cfg (with
+     ENTRY and EXIT):
+       test_fn ()
+       {
+         <bb 2>:
+	 D.65 = 42;
+
+	 <bb 3>:
+	 return D.65;
+       }
+     and then ought to merge blocks 2 and 3 in cleanup_tree_cfg.
+
+     Hence we should end up with a simple 3-block cfg, the two "fake" ones,
+     and a "real" one:
+       [ENTRY] -> [block2] -> [EXIT]
+     with code like this:
+	 test_fn ()
+	 {
+	   <bb 2>:
+	   D.56 = 42;
+	   return D.56;
+	 }
+  */
+  verify_three_block_gimple_cfg (fun);
+
+  /* Verify the statements within the "real" block.  */
+  basic_block bb2 = get_real_block (fun);
+  gimple *stmt_a = gimple_seq_first_stmt (bb_seq (bb2));
+  ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a));
+  gimple *stmt_b = stmt_a->next;
+  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt_b));
+  ASSERT_EQ (NULL, stmt_b->next);
+}
+
+/* Test of conversion of gimple to SSA form.  */
+
+static void
+test_conversion_to_ssa ()
+{
+  /* As above, construct a trivial function, gimplify it, and build a CFG: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  build_cfg (fndecl);
+
+  convert_to_ssa (fndecl);
+
+  verify_three_block_gimple_cfg (fun);
+
+  /* For out trivial test function we should now have something like
+     this:
+       test_fn ()
+       {
+	 <bb 2>:
+	 _1 = 42;
+	 return _1;
+       }
+  */
+  basic_block bb2 = get_real_block (fun);
+  gimple *stmt_a = gimple_seq_first_stmt (bb_seq (bb2));
+  ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a));
+
+  gimple *stmt_b = stmt_a->next;
+  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt_b));
+  ASSERT_EQ (NULL, stmt_b->next);
+
+  greturn *return_stmt = as_a <greturn *> (stmt_b);
+  ASSERT_EQ (SSA_NAME, TREE_CODE (gimple_return_retval (return_stmt)));
+}
+
+/* Test of expansion from gimple-ssa to RTL.  */
+
+static void
+test_expansion_to_rtl ()
+{
+  /* As above, construct a trivial function, gimplify it, build a CFG,
+     and convert to SSA: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  build_cfg (fndecl);
+  convert_to_ssa (fndecl);
+
+  /* We need a cgraph_node for it.  */
+  cgraph_node::get_create (fndecl);
+  /* Normally, cgraph_node::expand () would call
+     init_function_start (and a bunch of other stuff),
+     and invoke the expand pass, but it also runs
+     all of the other passes.  So just do the minimum
+     needed to get from gimple-SSA to RTL.  */
+  rtl_opt_pass *expand_pass = make_pass_expand (g);
+  push_cfun (fun);
+  init_function_start (fndecl);
+  expand_pass->execute (fun);
+  pop_cfun ();
+
+  /* On x86_64, I get this:
+       (note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+       (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
+       (insn 5 2 6 2 (set (reg:SI 87 [ D.59 ])
+			  (const_int 42 [0x2a])) -1 (nil))
+       (insn 6 5 10 2 (set (reg:SI 88 [ <retval> ])
+			   (reg:SI 87 [ D.59 ])) -1 (nil))
+       (insn 10 6 11 2 (set (reg/i:SI 0 ax)
+			    (reg:SI 88 [ <retval> ])) -1 (nil))
+       (insn 11 10 0 2 (use (reg/i:SI 0 ax)) -1 (nil))
+
+     On cr16-elf I get this:
+       (note 4 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+       (insn 2 4 3 2 (set (reg:SI 24)
+	    (reg/f:SI 16 virtual-incoming-args)) -1
+	  (nil))
+       (note 3 2 6 2 NOTE_INSN_FUNCTION_BEG)
+       (insn 6 3 7 2 (set (reg:HI 22 [ _1 ])
+	    (const_int 42 [0x2a])) -1
+	 (nil))
+       (insn 7 6 11 2 (set (reg:HI 23 [ <retval> ])
+	   (reg:HI 22 [ _1 ])) -1
+	 (nil))
+       (insn 11 7 12 2 (set (reg/i:HI 0 r0)
+	   (reg:HI 23 [ <retval> ])) -1
+	 (nil))
+       (insn 12 11 0 2 (use (reg/i:HI 0 r0)) -1
+	 (nil)).  */
+  verify_three_block_rtl_cfg (fun);
+
+  /* Verify as much of the RTL as we can whilst avoiding
+     target-specific behavior.  */
+  basic_block bb2 = get_real_block (fun);
+
+  /* Expect a NOTE_INSN_BASIC_BLOCK... */
+  rtx_insn *insn = BB_HEAD (bb2);
+  ASSERT_TRUE (insn != NULL);
+  ASSERT_EQ (NOTE, insn->code);
+  ASSERT_EQ (NOTE_INSN_BASIC_BLOCK, NOTE_KIND (insn));
+  ASSERT_EQ (bb2, NOTE_BASIC_BLOCK (insn));
+
+  /* ...etc; any further checks are likely to over-specify things
+     and run us into target dependencies.  */
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+function_tests_c_tests ()
+{
+  test_fndecl_int_void ();
+  test_fndecl_float_intchar ();
+  test_gimplification ();
+  test_building_cfg ();
+  test_conversion_to_ssa ();
+  test_expansion_to_rtl ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 226b080..803b34b 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-walk.h"
 #include "gimplify.h"
 #include "target.h"
+#include "selftest.h"
+#include "gimple-pretty-print.h"
 
 
 /* All the tuples have their operand vector (if present) at the very bottom
@@ -3018,3 +3020,138 @@ maybe_remove_unused_call_args (struct function *fn, gimple *stmt)
       update_stmt_fn (fn, stmt);
     }
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests for core gimple structures.  */
+
+/* Verify that STMT is pretty-printed as EXPECTED.
+   Helper function for selftests.  */
+
+static void
+verify_gimple_pp (const char *expected, gimple *stmt)
+{
+  pretty_printer pp;
+  pp_gimple_stmt_1 (&pp, stmt, 0 /* spc */, 0 /* flags */);
+  ASSERT_STREQ (expected, pp_formatted_text (&pp));
+}
+
+/* Build a GIMPLE_ASSIGN equivalent to
+     tmp = 5;
+   and verify various properties of it.  */
+
+static void
+test_assign_single ()
+{
+  tree type = integer_type_node;
+  tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			 get_identifier ("tmp"),
+			 type);
+  tree rhs = build_int_cst (type, 5);
+  gassign *stmt = gimple_build_assign (lhs, rhs);
+  verify_gimple_pp ("tmp = 5;", stmt);
+
+  ASSERT_TRUE (is_gimple_assign (stmt));
+  ASSERT_EQ (lhs, gimple_assign_lhs (stmt));
+  ASSERT_EQ (lhs, gimple_get_lhs (stmt));
+  ASSERT_EQ (rhs, gimple_assign_rhs1 (stmt));
+  ASSERT_EQ (NULL, gimple_assign_rhs2 (stmt));
+  ASSERT_EQ (NULL, gimple_assign_rhs3 (stmt));
+  ASSERT_TRUE (gimple_assign_single_p (stmt));
+  ASSERT_EQ (INTEGER_CST, gimple_assign_rhs_code (stmt));
+}
+
+/* Build a GIMPLE_ASSIGN equivalent to
+     tmp = a * b;
+   and verify various properties of it.  */
+
+static void
+test_assign_binop ()
+{
+  tree type = integer_type_node;
+  tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			 get_identifier ("tmp"),
+			 type);
+  tree a = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		       get_identifier ("a"),
+		       type);
+  tree b = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		       get_identifier ("b"),
+		       type);
+  gassign *stmt = gimple_build_assign (lhs, MULT_EXPR, a, b);
+  verify_gimple_pp ("tmp = a * b;", stmt);
+
+  ASSERT_TRUE (is_gimple_assign (stmt));
+  ASSERT_EQ (lhs, gimple_assign_lhs (stmt));
+  ASSERT_EQ (lhs, gimple_get_lhs (stmt));
+  ASSERT_EQ (a, gimple_assign_rhs1 (stmt));
+  ASSERT_EQ (b, gimple_assign_rhs2 (stmt));
+  ASSERT_EQ (NULL, gimple_assign_rhs3 (stmt));
+  ASSERT_FALSE (gimple_assign_single_p (stmt));
+  ASSERT_EQ (MULT_EXPR, gimple_assign_rhs_code (stmt));
+}
+
+/* Build a GIMPLE_NOP and verify various properties of it.  */
+
+static void
+test_nop_stmt ()
+{
+  gimple *stmt = gimple_build_nop ();
+  verify_gimple_pp ("GIMPLE_NOP", stmt);
+  ASSERT_EQ (GIMPLE_NOP, gimple_code (stmt));
+  ASSERT_EQ (NULL, gimple_get_lhs (stmt));
+  ASSERT_FALSE (gimple_assign_single_p (stmt));
+}
+
+/* Build a GIMPLE_RETURN equivalent to
+     return 7;
+   and verify various properties of it.  */
+
+static void
+test_return_stmt ()
+{
+  tree type = integer_type_node;
+  tree val = build_int_cst (type, 7);
+  greturn *stmt = gimple_build_return (val);
+  verify_gimple_pp ("return 7;", stmt);
+
+  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt));
+  ASSERT_EQ (NULL, gimple_get_lhs (stmt));
+  ASSERT_EQ (val, gimple_return_retval (stmt));
+  ASSERT_FALSE (gimple_assign_single_p (stmt));
+}
+
+/* Build a GIMPLE_RETURN equivalent to
+     return;
+   and verify various properties of it.  */
+
+static void
+test_return_without_value ()
+{
+  greturn *stmt = gimple_build_return (NULL);
+  verify_gimple_pp ("return;", stmt);
+
+  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt));
+  ASSERT_EQ (NULL, gimple_get_lhs (stmt));
+  ASSERT_EQ (NULL, gimple_return_retval (stmt));
+  ASSERT_FALSE (gimple_assign_single_p (stmt));
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+gimple_c_tests ()
+{
+  test_assign_single ();
+  test_assign_binop ();
+  test_nop_stmt ();
+  test_return_stmt ();
+  test_return_without_value ();
+}
+
+} // namespace selftest
+
+
+#endif /* CHECKING_P */
diff --git a/gcc/hash-map-tests.c b/gcc/hash-map-tests.c
new file mode 100644
index 0000000..fd1bb95
--- /dev/null
+++ b/gcc/hash-map-tests.c
@@ -0,0 +1,93 @@
+/* Unit tests for hash-map.h.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Construct a hash_map <const char *, int> and verify that
+   various operations work correctly.  */
+
+static void
+test_map_of_strings_to_int ()
+{
+  hash_map <const char *, int> m;
+
+  const char *ostrich = "ostrich";
+  const char *elephant = "elephant";
+  const char *ant = "ant";
+  const char *spider = "spider";
+  const char *millipede = "Illacme plenipes";
+  const char *eric = "half a bee";
+
+  /* A fresh hash_map should be empty.  */
+  ASSERT_EQ (0, m.elements ());
+  ASSERT_EQ (NULL, m.get (ostrich));
+
+  /* Populate the hash_map.  */
+  ASSERT_EQ (false, m.put (ostrich, 2));
+  ASSERT_EQ (false, m.put (elephant, 4));
+  ASSERT_EQ (false, m.put (ant, 6));
+  ASSERT_EQ (false, m.put (spider, 8));
+  ASSERT_EQ (false, m.put (millipede, 750));
+  ASSERT_EQ (false, m.put (eric, 3));
+
+  /* Verify that we can recover the stored values.  */
+  ASSERT_EQ (6, m.elements ());
+  ASSERT_EQ (2, *m.get (ostrich));
+  ASSERT_EQ (4, *m.get (elephant));
+  ASSERT_EQ (6, *m.get (ant));
+  ASSERT_EQ (8, *m.get (spider));
+  ASSERT_EQ (750, *m.get (millipede));
+  ASSERT_EQ (3, *m.get (eric));
+
+  /* Verify removing an item.  */
+  m.remove (eric);
+  ASSERT_EQ (5, m.elements ());
+  ASSERT_EQ (NULL, m.get (eric));
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+hash_map_tests_c_tests ()
+{
+  test_map_of_strings_to_int ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
diff --git a/gcc/hash-set-tests.c b/gcc/hash-set-tests.c
new file mode 100644
index 0000000..db408f2
--- /dev/null
+++ b/gcc/hash-set-tests.c
@@ -0,0 +1,69 @@
+/* Unit tests for hash-set.h.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Construct a hash_set <const char *> and verify that various operations
+   work correctly.  */
+
+static void
+test_set_of_strings ()
+{
+  hash_set <const char *> s;
+  ASSERT_EQ (0, s.elements ());
+
+  const char *red = "red";
+  const char *green = "green";
+  const char *blue = "blue";
+
+  ASSERT_EQ (false, s.contains (red));
+
+  /* Populate the hash_set.  */
+  ASSERT_EQ (false, s.add (red));
+  ASSERT_EQ (false, s.add (green));
+  ASSERT_EQ (false, s.add (blue));
+
+  /* Verify that the values are now within the set.  */
+  ASSERT_EQ (true, s.contains (red));
+  ASSERT_EQ (true, s.contains (green));
+  ASSERT_EQ (true, s.contains (blue));
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+hash_set_tests_c_tests ()
+{
+  test_set_of_strings ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/input.c b/gcc/input.c
index 61b1e44..0b340a8 100644
--- a/gcc/input.c
+++ b/gcc/input.c
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "intl.h"
 #include "diagnostic-core.h"
+#include "selftest.h"
 
 /* This is a cache used by get_next_line to store the content of a
    file to be searched for file lines.  */
@@ -1136,3 +1137,118 @@ dump_location_info (FILE *stream)
   dump_labelled_location_range (stream, "AD-HOC LOCATIONS",
 				MAX_SOURCE_LOCATION + 1, UINT_MAX);
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests of location handling.  */
+
+/* Verify the result of LOCATION_FILE/LOCATION_LINE/LOCATION_COLUMN
+   on LOC.  */
+
+static void
+assert_loceq (const char *exp_filename, int exp_linenum, int exp_colnum,
+	      location_t loc)
+{
+  ASSERT_STREQ (exp_filename, LOCATION_FILE (loc));
+  ASSERT_EQ (exp_linenum, LOCATION_LINE (loc));
+  ASSERT_EQ (exp_colnum, LOCATION_COLUMN (loc));
+}
+
+/* Verify basic operation of ordinary linemaps.  */
+
+static void
+test_accessing_ordinary_linemaps ()
+{
+  /* Build a simple linemap describing some locations. */
+  linemap_add (line_table, LC_ENTER, false, "foo.c", 0);
+
+  linemap_line_start (line_table, 1, 100);
+  location_t loc_a = linemap_position_for_column (line_table, 1);
+  location_t loc_b = linemap_position_for_column (line_table, 23);
+
+  linemap_line_start (line_table, 2, 100);
+  location_t loc_c = linemap_position_for_column (line_table, 1);
+  location_t loc_d = linemap_position_for_column (line_table, 17);
+
+  /* Example of a very long line.  */
+  linemap_line_start (line_table, 3, 2000);
+  location_t loc_e = linemap_position_for_column (line_table, 700);
+
+  linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+
+  /* Multiple files.  */
+  linemap_add (line_table, LC_ENTER, false, "bar.c", 0);
+  linemap_line_start (line_table, 1, 200);
+  location_t loc_f = linemap_position_for_column (line_table, 150);
+  linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+
+  /* Verify that we can recover the location info.  */
+  assert_loceq ("foo.c", 1, 1, loc_a);
+  assert_loceq ("foo.c", 1, 23, loc_b);
+  assert_loceq ("foo.c", 2, 1, loc_c);
+  assert_loceq ("foo.c", 2, 17, loc_d);
+  assert_loceq ("foo.c", 3, 700, loc_e);
+  assert_loceq ("bar.c", 1, 150, loc_f);
+
+  ASSERT_FALSE (is_location_from_builtin_token (loc_a));
+}
+
+/* Verify various properties of UNKNOWN_LOCATION.  */
+
+static void
+test_unknown_location ()
+{
+  ASSERT_EQ (NULL, LOCATION_FILE (UNKNOWN_LOCATION));
+  ASSERT_EQ (0, LOCATION_LINE (UNKNOWN_LOCATION));
+  ASSERT_EQ (0, LOCATION_COLUMN (UNKNOWN_LOCATION));
+}
+
+/* Verify various properties of BUILTINS_LOCATION.  */
+
+static void
+test_builtins ()
+{
+  assert_loceq ("<built-in>", 0, 0, BUILTINS_LOCATION);
+  ASSERT_PRED1 (is_location_from_builtin_token, BUILTINS_LOCATION);
+}
+
+/* Verify reading of input files (e.g. for caret-based diagnostics).  */
+
+static void
+test_reading_source_line ()
+{
+  /* We will read *this* source file, using __FILE__.
+     Here is some specific text to read and test for:
+     The quick brown fox jumps over the lazy dog.  */
+  const int linenum_after_test_message = __LINE__;
+  const int linenum = linenum_after_test_message - 1;
+
+  int line_size;
+  const char *source_line = location_get_source_line (__FILE__, linenum, &line_size);
+  ASSERT_TRUE (source_line != NULL);
+  ASSERT_EQ (53, line_size);
+  if (!strncmp ("     The quick brown fox jumps over the lazy dog.  */",
+	       source_line, line_size))
+    ::selftest::pass (__FILE__, __LINE__,
+		      "source_line matched expected value");
+  else
+    ::selftest::fail (__FILE__, __LINE__,
+		      "source_line did not match expected value");
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+input_c_tests ()
+{
+  test_accessing_ordinary_linemaps ();
+  test_unknown_location ();
+  test_builtins ();
+  test_reading_source_line ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
diff --git a/gcc/rtl-tests.c b/gcc/rtl-tests.c
new file mode 100644
index 0000000..3e9ebae
--- /dev/null
+++ b/gcc/rtl-tests.c
@@ -0,0 +1,117 @@
+/* Unit tests for RTL-handling.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "pretty-print.h"
+#include "cfgbuild.h"
+#include "print-rtl.h"
+#include "selftest.h"
+#include "function.h"
+#include "emit-rtl.h"
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Verify that PAT is printed as EXPECTED.  Helper function for
+   selftests.  */
+
+static void
+verify_print_pattern (const char *expected, rtx pat)
+{
+  pretty_printer pp;
+  print_pattern (&pp, pat, 1);
+  ASSERT_STREQ (expected, pp_formatted_text (&pp));
+}
+
+/* Unit testing of "single_set".  */
+
+static void
+test_single_set ()
+{
+  /* A label is not a SET.  */
+  ASSERT_EQ (NULL_RTX, single_set (gen_label_rtx ()));
+
+  /* An unconditional jump insn is a single SET.  */
+  rtx set_pc = gen_rtx_SET (pc_rtx,
+			    gen_rtx_LABEL_REF (VOIDmode,
+					       gen_label_rtx ()));
+  rtx_insn *jump_insn = emit_jump_insn (set_pc);
+  ASSERT_EQ (set_pc, single_set (jump_insn));
+
+  /* etc */
+}
+
+/* Construct an unconditional jump to a label, and verify that
+   various properties of it are sane.  */
+
+static void
+test_uncond_jump ()
+{
+  rtx_insn *label = gen_label_rtx ();
+  rtx jump_pat = gen_rtx_SET (pc_rtx,
+			      gen_rtx_LABEL_REF (VOIDmode,
+						 label));
+  ASSERT_EQ (SET, jump_pat->code);
+  ASSERT_EQ (LABEL_REF, SET_SRC (jump_pat)->code);
+  ASSERT_EQ (label, LABEL_REF_LABEL (SET_SRC (jump_pat)));
+  ASSERT_EQ (PC, SET_DEST (jump_pat)->code);
+
+  verify_print_pattern ("pc=L0", jump_pat);
+
+  rtx_insn *jump_insn = emit_jump_insn (jump_pat);
+  ASSERT_FALSE (any_condjump_p (jump_insn));
+  ASSERT_TRUE (any_uncondjump_p (jump_insn));
+  ASSERT_TRUE (pc_set (jump_insn));
+  ASSERT_TRUE (simplejump_p (jump_insn));
+  ASSERT_TRUE (onlyjump_p (jump_insn));
+  ASSERT_TRUE (control_flow_insn_p (jump_insn));
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+rtl_tests_c_tests ()
+{
+  test_single_set ();
+  test_uncond_jump ();
+
+  /* Purge state.  */
+  set_first_insn (NULL);
+  set_last_insn (NULL);
+}
+
+} // namespace selftest
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
new file mode 100644
index 0000000..ab334aa
--- /dev/null
+++ b/gcc/selftest-run-tests.c
@@ -0,0 +1,77 @@
+/* Implementation of selftests.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "selftest.h"
+
+/* This function needed to be split out from selftest.c as it references
+   tests from the whole source tree, and so is within
+   OBJS in Makefile.in, whereas selftest.o is within OBJS-libcommon.
+   This allows us to embed tests within files in OBJS-libcommon without
+   introducing a dependency on objects within OBJS.  */
+
+#if CHECKING_P
+
+/* Run all tests, aborting if any fail.  */
+
+void
+selftest::run_tests ()
+{
+  long start_time = get_run_time ();
+
+  /* Run all the tests, in hand-coded order of (approximate) dependencies:
+     run the tests for lowest-level code first.  */
+
+  /* Low-level data structures.  */
+  bitmap_c_tests ();
+  et_forest_c_tests ();
+  hash_map_tests_c_tests ();
+  hash_set_tests_c_tests ();
+  vec_c_tests ();
+  wide_int_cc_tests ();
+
+  /* Mid-level data structures.  */
+  input_c_tests ();
+  tree_c_tests ();
+  gimple_c_tests ();
+  rtl_tests_c_tests ();
+
+  /* Higher-level tests, or for components that other selftests don't
+     rely on.  */
+  diagnostic_show_locus_c_tests ();
+  fold_const_c_tests ();
+  spellcheck_c_tests ();
+  tree_cfg_c_tests ();
+
+  /* This one relies on most of the above.  */
+  function_tests_c_tests ();
+
+  /* Finished running tests.  */
+  long finish_time = get_run_time ();
+  long elapsed_time = finish_time - start_time;
+
+  fprintf (stderr,
+	   "-fself-test: %i pass(es) in %ld.%06ld seconds\n",
+	   num_passes,
+	   elapsed_time / 1000000, elapsed_time % 1000000);
+}
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest.c b/gcc/selftest.c
new file mode 100644
index 0000000..de804df
--- /dev/null
+++ b/gcc/selftest.c
@@ -0,0 +1,47 @@
+/* A self-testing framework, for use by -fself-test.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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 "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+int selftest::num_passes;
+
+/* Record the successful outcome of some aspect of a test.  */
+
+void
+selftest::pass (const char */*file*/, int /*line*/, const char */*msg*/)
+{
+  num_passes++;
+}
+
+/* Report the failed outcome of some aspect of a test and abort.  */
+
+void
+selftest::fail (const char *file, int line, const char *msg)
+{
+  fprintf (stderr,"%s:%i: FAIL: %s\n", file, line, msg);
+  /* TODO: add calling function name as well?  */
+  abort ();
+}
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest.h b/gcc/selftest.h
new file mode 100644
index 0000000..a1d3074
--- /dev/null
+++ b/gcc/selftest.h
@@ -0,0 +1,153 @@
+/* A self-testing framework, for use by -fself-test.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+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/>.  */
+
+#ifndef GCC_SELFTEST_H
+#define GCC_SELFTEST_H
+
+/* The selftest code should entirely disappear in a production
+   configuration, hence we guard all of it with #if CHECKING_P.  */
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* The entrypoint for running all tests.  */
+
+extern void run_tests ();
+
+/* Record the successful outcome of some aspect of the test.  */
+
+extern void pass (const char *file, int line, const char *msg);
+
+/* Report the failed outcome of some aspect of the test and abort.  */
+
+extern void fail (const char *file, int line, const char *msg);
+
+/* Declarations for specific families of tests (by source file), in
+   alphabetical order.  */
+extern void bitmap_c_tests ();
+extern void diagnostic_show_locus_c_tests ();
+extern void et_forest_c_tests ();
+extern void fold_const_c_tests ();
+extern void function_tests_c_tests ();
+extern void gimple_c_tests ();
+extern void hash_map_tests_c_tests ();
+extern void hash_set_tests_c_tests ();
+extern void input_c_tests ();
+extern void rtl_tests_c_tests ();
+extern void spellcheck_c_tests ();
+extern void tree_c_tests ();
+extern void tree_cfg_c_tests ();
+extern void vec_c_tests ();
+extern void wide_int_cc_tests ();
+
+extern int num_passes;
+
+} /* end of namespace selftest.  */
+
+/* Macros for writing tests.  */
+
+/* Evaluate EXPR and coerce to bool, calling
+   ::selftest::pass if it is true,
+   ::selftest::fail if it false.  */
+
+#define ASSERT_TRUE(EXPR)				\
+  SELFTEST_BEGIN_STMT					\
+  const char *desc = "ASSERT_TRUE (" #EXPR ")";		\
+  bool actual = (EXPR);					\
+  if (actual)						\
+    ::selftest::pass (__FILE__, __LINE__, desc);	\
+  else							\
+    ::selftest::fail (__FILE__, __LINE__, desc);		\
+  SELFTEST_END_STMT
+
+/* Evaluate EXPR and coerce to bool, calling
+   ::selftest::pass if it is false,
+   ::selftest::fail if it true.  */
+
+#define ASSERT_FALSE(EXPR)					\
+  SELFTEST_BEGIN_STMT						\
+  const char *desc = "ASSERT_FALSE (" #EXPR ")";		\
+  bool actual = (EXPR);					\
+  if (actual)							\
+    ::selftest::fail (__FILE__, __LINE__, desc);				\
+  else								\
+    ::selftest::pass (__FILE__, __LINE__, desc);				\
+  SELFTEST_END_STMT
+
+/* Evaluate EXPECTED and ACTUAL and compare them with ==, calling
+   ::selftest::pass if they are equal,
+   ::selftest::fail if they are non-equal.  */
+
+#define ASSERT_EQ(EXPECTED, ACTUAL)			       \
+  SELFTEST_BEGIN_STMT					       \
+  const char *desc = "ASSERT_EQ (" #EXPECTED ", " #ACTUAL ")"; \
+  if ((EXPECTED) == (ACTUAL))				       \
+    ::selftest::pass (__FILE__, __LINE__, desc);			       \
+  else							       \
+    ::selftest::fail (__FILE__, __LINE__, desc);			       \
+  SELFTEST_END_STMT
+
+/* Evaluate EXPECTED and ACTUAL and compare them with !=, calling
+   ::selftest::pass if they are non-equal,
+   ::selftest::fail if they are equal.  */
+
+#define ASSERT_NE(EXPECTED, ACTUAL)			       \
+  SELFTEST_BEGIN_STMT					       \
+  const char *desc = "ASSERT_NE (" #EXPECTED ", " #ACTUAL ")"; \
+  if ((EXPECTED) != (ACTUAL))				       \
+    ::selftest::pass (__FILE__, __LINE__, desc);			       \
+  else							       \
+    ::selftest::fail (__FILE__, __LINE__, desc);			       \
+  SELFTEST_END_STMT
+
+/* Evaluate EXPECTED and ACTUAL and compare them with strcmp, calling
+   ::selftest::pass if they are equal,
+   ::selftest::fail if they are non-equal.  */
+
+#define ASSERT_STREQ(EXPECTED, ACTUAL)			       \
+  SELFTEST_BEGIN_STMT					       \
+  const char *desc = "ASSERT_STREQ (" #EXPECTED ", " #ACTUAL ")"; \
+  const char *expected_ = (EXPECTED);				  \
+  const char *actual_ = (ACTUAL);				  \
+  if (0 == strcmp (expected_, actual_))				  \
+    ::selftest::pass (__FILE__, __LINE__, desc);			       \
+  else							       \
+    ::selftest::fail (__FILE__, __LINE__, desc);			       \
+  SELFTEST_END_STMT
+
+/* Evaluate PRED1 (VAL1), calling ::selftest::pass if it is true,
+   ::selftest::fail if it is false.  */
+
+#define ASSERT_PRED1(PRED1, VAL1)			\
+  SELFTEST_BEGIN_STMT					\
+  const char *desc = "ASSERT_PRED1 (" #PRED1 ", " #VAL1 ")";	\
+  bool actual = (PRED1) (VAL1);				\
+  if (actual)						\
+    ::selftest::pass (__FILE__, __LINE__, desc);			\
+  else							\
+    ::selftest::fail (__FILE__, __LINE__, desc);			\
+  SELFTEST_END_STMT
+
+#define SELFTEST_BEGIN_STMT do {
+#define SELFTEST_END_STMT   } while (0)
+
+#endif /* #if CHECKING_P */
+
+#endif /* GCC_SELFTEST_H */
diff --git a/gcc/spellcheck.c b/gcc/spellcheck.c
index e4e83a5..ceb6016 100644
--- a/gcc/spellcheck.c
+++ b/gcc/spellcheck.c
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "tree.h"
 #include "spellcheck.h"
+#include "selftest.h"
 
 /* The Levenshtein distance is an "edit-distance": the minimal
    number of one-character insertions, removals or substitutions
@@ -165,3 +166,60 @@ find_closest_string (const char *target,
 
   return best_candidate;
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests.  */
+
+/* Verify that the levenshtein_distance (A, B) equals the expected
+   value.  */
+
+static void
+levenshtein_distance_unit_test_oneway (const char *a, const char *b,
+				       edit_distance_t expected)
+{
+  edit_distance_t actual = levenshtein_distance (a, b);
+  ASSERT_EQ (actual, expected);
+}
+
+/* Verify that both
+     levenshtein_distance (A, B)
+   and
+     levenshtein_distance (B, A)
+   equal the expected value, to ensure that the function is symmetric.  */
+
+static void
+levenshtein_distance_unit_test (const char *a, const char *b,
+				edit_distance_t expected)
+{
+  levenshtein_distance_unit_test_oneway (a, b, expected);
+  levenshtein_distance_unit_test_oneway (b, a, expected);
+}
+
+/* Verify levenshtein_distance for a variety of pairs of pre-canned
+   inputs, comparing against known-good values.  */
+
+void
+spellcheck_c_tests ()
+{
+  levenshtein_distance_unit_test ("", "nonempty", strlen ("nonempty"));
+  levenshtein_distance_unit_test ("saturday", "sunday", 3);
+  levenshtein_distance_unit_test ("foo", "m_foo", 2);
+  levenshtein_distance_unit_test ("hello_world", "HelloWorld", 3);
+  levenshtein_distance_unit_test
+    ("the quick brown fox jumps over the lazy dog", "dog", 40);
+  levenshtein_distance_unit_test
+    ("the quick brown fox jumps over the lazy dog",
+     "the quick brown dog jumps over the lazy fox",
+     4);
+  levenshtein_distance_unit_test
+    ("Lorem ipsum dolor sit amet, consectetur adipiscing elit,",
+     "All your base are belong to us",
+     44);
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c b/gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c
deleted file mode 100644
index ac49992..0000000
--- a/gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c
+++ /dev/null
@@ -1,9 +0,0 @@
-/* Placeholder C source file for unit-testing gcc/spellcheck.c.  */
-/* { dg-do compile } */
-/* { dg-options "-O" } */
-
-int
-main (int argc, char **argv)
-{
-  return 0;
-}
diff --git a/gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c b/gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c
deleted file mode 100644
index 3e7dc78..0000000
--- a/gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Plugin for unittesting gcc/spellcheck.h.  */
-
-#include "config.h"
-#include "gcc-plugin.h"
-#include "system.h"
-#include "coretypes.h"
-#include "spellcheck.h"
-#include "diagnostic.h"
-
-int plugin_is_GPL_compatible;
-
-static void
-levenshtein_distance_unit_test_oneway (const char *a, const char *b,
-				       edit_distance_t expected)
-{
-  edit_distance_t actual = levenshtein_distance (a, b);
-  if (actual != expected)
-    error ("levenshtein_distance (\"%s\", \"%s\") : expected: %i got %i",
-	   a, b, expected, actual);
-}
-
-
-static void
-levenshtein_distance_unit_test (const char *a, const char *b,
-				edit_distance_t expected)
-{
-  /* Run every test both ways to ensure it's symmetric.  */
-  levenshtein_distance_unit_test_oneway (a, b, expected);
-  levenshtein_distance_unit_test_oneway (b, a, expected);
-}
-
-/* Callback handler for the PLUGIN_FINISH event; run
-   levenshtein_distance unit tests here.  */
-
-static void
-on_finish (void */*gcc_data*/, void */*user_data*/)
-{
-  levenshtein_distance_unit_test ("", "nonempty", strlen ("nonempty"));
-  levenshtein_distance_unit_test ("saturday", "sunday", 3);
-  levenshtein_distance_unit_test ("foo", "m_foo", 2);
-  levenshtein_distance_unit_test ("hello_world", "HelloWorld", 3);
-  levenshtein_distance_unit_test
-    ("the quick brown fox jumps over the lazy dog", "dog", 40);
-  levenshtein_distance_unit_test
-    ("the quick brown fox jumps over the lazy dog",
-     "the quick brown dog jumps over the lazy fox",
-     4);
-  levenshtein_distance_unit_test
-    ("Lorem ipsum dolor sit amet, consectetur adipiscing elit,",
-     "All your base are belong to us",
-     44);
-}
-
-int
-plugin_init (struct plugin_name_args *plugin_info,
-	     struct plugin_gcc_version */*version*/)
-{
-  register_callback (plugin_info->base_name,
-		     PLUGIN_FINISH,
-		     on_finish,
-		     NULL); /* void *user_data */
-
-  return 0;
-}
diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp
index 321b4ba..be2ac8d 100644
--- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
+++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
@@ -70,7 +70,6 @@ set plugin_test_list [list \
 	  diagnostic-test-expressions-1.c } \
     { diagnostic_plugin_show_trees.c \
 	  diagnostic-test-show-trees-1.c } \
-    { levenshtein_plugin.c levenshtein-test-1.c } \
     { location_overflow_plugin.c \
 	  location-overflow-test-1.c \
 	  location-overflow-test-2.c } \
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 230878e..543b8a3 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -87,6 +87,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "xcoffout.h"		/* Needed for external data declarations. */
 #endif
 
+#include "selftest.h"
+
 static void general_init (const char *, bool);
 static void do_compile ();
 static void process_options (void);
@@ -2031,6 +2033,27 @@ toplev::start_timevars ()
   timevar_start (TV_TOTAL);
 }
 
+/* Handle -fself-test.   */
+
+void
+toplev::run_self_tests ()
+{
+#if CHECKING_P
+  /* Reset some state.  */
+  input_location = UNKNOWN_LOCATION;
+  bitmap_obstack_initialize (NULL);
+
+  /* Run the tests; any failures will lead to an abort of the process.
+     Use "make selftests-gdb" to run under the debugger.  */
+  ::selftest::run_tests ();
+
+  /* Cleanup.  */
+  bitmap_obstack_release (NULL);
+#else
+  inform (UNKNOWN_LOCATION, "self-tests are not enabled in this build");
+#endif /* #if CHECKING_P */
+}
+
 /* Entry point of cc1, cc1plus, jc1, f771, etc.
    Exit code is FATAL_EXIT_CODE if can't open files or if there were
    any errors, or SUCCESS_EXIT_CODE if compilation succeeded.
@@ -2098,6 +2121,9 @@ toplev::main (int argc, char **argv)
   if (warningcount || errorcount || werrorcount)
     print_ignored_options ();
 
+  if (flag_self_test)
+    run_self_tests ();
+
   /* Invoke registered plugin callbacks if any.  Some plugins could
      emit some diagnostics here.  */
   invoke_plugin_callbacks (PLUGIN_FINISH, NULL);
diff --git a/gcc/toplev.h b/gcc/toplev.h
index 0beb06e..06923cf 100644
--- a/gcc/toplev.h
+++ b/gcc/toplev.h
@@ -42,6 +42,8 @@ private:
 
   void start_timevars ();
 
+  void run_self_tests ();
+
   bool m_use_TV_TOTAL;
   bool m_init_signals;
 };
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 7fc24ba..40e524b 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -58,6 +58,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-cfgcleanup.h"
 #include "gimplify.h"
 #include "attribs.h"
+#include "selftest.h"
 
 /* This file contains functions for building the Control Flow Graph (CFG)
    for a function tree.  */
@@ -9195,3 +9196,280 @@ gt_pch_nx (edge_def *e, gt_pointer_operator op, void *cookie)
     op (&(e->insns.r), cookie);
   op (&(block), cookie);
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Helper function for CFG selftests: create a dummy function decl
+   and push it as cfun.  */
+
+static tree
+push_fndecl (const char *name)
+{
+  tree fn_type = build_function_type_array (integer_type_node, 0, NULL);
+  /* FIXME: this uses input_location: */
+  tree fndecl = build_fn_decl (name, fn_type);
+  tree retval = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+			    NULL_TREE, integer_type_node);
+  DECL_RESULT (fndecl) = retval;
+  push_struct_function (fndecl);
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  init_empty_tree_cfg_for_function (fun);
+  ASSERT_EQ (2, n_basic_blocks_for_fn (fun));
+  ASSERT_EQ (0, n_edges_for_fn (fun));
+  return fndecl;
+}
+
+/* These tests directly create CFGs.
+   Compare with the static fns within tree-cfg.c:
+     - build_gimple_cfg
+     - make_blocks: calls create_basic_block (seq, bb);
+     - make_edges.   */
+
+/* Verify a simple cfg of the form:
+     ENTRY -> A -> B -> C -> EXIT.  */
+
+static void
+test_linear_chain ()
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_test_linear_chain");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+
+  /* Create some empty blocks.  */
+  basic_block bb_a = create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun));
+  basic_block bb_b = create_empty_bb (bb_a);
+  basic_block bb_c = create_empty_bb (bb_b);
+
+  ASSERT_EQ (5, n_basic_blocks_for_fn (fun));
+  ASSERT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create some edges: a simple linear chain of BBs.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), bb_a, EDGE_FALLTHRU);
+  make_edge (bb_a, bb_b, 0);
+  make_edge (bb_b, bb_c, 0);
+  make_edge (bb_c, EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+
+  /* Verify the edges.  */
+  ASSERT_EQ (4, n_edges_for_fn (fun));
+  ASSERT_EQ (NULL, ENTRY_BLOCK_PTR_FOR_FN (fun)->preds);
+  ASSERT_EQ (1, ENTRY_BLOCK_PTR_FOR_FN (fun)->succs->length ());
+  ASSERT_EQ (1, bb_a->preds->length ());
+  ASSERT_EQ (1, bb_a->succs->length ());
+  ASSERT_EQ (1, bb_b->preds->length ());
+  ASSERT_EQ (1, bb_b->succs->length ());
+  ASSERT_EQ (1, bb_c->preds->length ());
+  ASSERT_EQ (1, bb_c->succs->length ());
+  ASSERT_EQ (1, EXIT_BLOCK_PTR_FOR_FN (fun)->preds->length ());
+  ASSERT_EQ (NULL, EXIT_BLOCK_PTR_FOR_FN (fun)->succs);
+
+  /* Verify the dominance information
+     Each BB in our simple chain should be dominated by the one before
+     it.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
+  ASSERT_EQ (bb_b, get_immediate_dominator (CDI_DOMINATORS, bb_c));
+  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
+  ASSERT_EQ (1, dom_by_b.length ());
+  ASSERT_EQ (bb_c, dom_by_b[0]);
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance: each BB in our chain is post-dominated
+     by the one after it.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  ASSERT_EQ (bb_b, get_immediate_dominator (CDI_POST_DOMINATORS, bb_a));
+  ASSERT_EQ (bb_c, get_immediate_dominator (CDI_POST_DOMINATORS, bb_b));
+  vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
+  ASSERT_EQ (1, postdom_by_b.length ());
+  ASSERT_EQ (bb_a, postdom_by_b[0]);
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+/* Verify a simple CFG of the form:
+     ENTRY
+       |
+       A
+      / \
+     /t  \f
+    B     C
+     \   /
+      \ /
+       D
+       |
+      EXIT.  */
+
+static void
+test_diamond ()
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_test_diamond");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+
+  /* Create some empty blocks.  */
+  basic_block bb_a = create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun));
+  basic_block bb_b = create_empty_bb (bb_a);
+  basic_block bb_c = create_empty_bb (bb_a);
+  basic_block bb_d = create_empty_bb (bb_b);
+
+  ASSERT_EQ (6, n_basic_blocks_for_fn (fun));
+  ASSERT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create the edges.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), bb_a, EDGE_FALLTHRU);
+  make_edge (bb_a, bb_b, EDGE_TRUE_VALUE);
+  make_edge (bb_a, bb_c, EDGE_FALSE_VALUE);
+  make_edge (bb_b, bb_d, 0);
+  make_edge (bb_c, bb_d, 0);
+  make_edge (bb_d, EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+
+  /* Verify the edges.  */
+  ASSERT_EQ (6, n_edges_for_fn (fun));
+  ASSERT_EQ (1, bb_a->preds->length ());
+  ASSERT_EQ (2, bb_a->succs->length ());
+  ASSERT_EQ (1, bb_b->preds->length ());
+  ASSERT_EQ (1, bb_b->succs->length ());
+  ASSERT_EQ (1, bb_c->preds->length ());
+  ASSERT_EQ (1, bb_c->succs->length ());
+  ASSERT_EQ (2, bb_d->preds->length ());
+  ASSERT_EQ (1, bb_d->succs->length ());
+
+  /* Verify the dominance information.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
+  ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_c));
+  ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_d));
+  vec<basic_block> dom_by_a = get_dominated_by (CDI_DOMINATORS, bb_a);
+  ASSERT_EQ (3, dom_by_a.length ()); /* B, C, D, in some order.  */
+  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
+  ASSERT_EQ (0, dom_by_b.length ());
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_a));
+  ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_b));
+  ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_c));
+  vec<basic_block> postdom_by_d = get_dominated_by (CDI_POST_DOMINATORS, bb_d);
+  ASSERT_EQ (3, postdom_by_d.length ()); /* A, B, C in some order.  */
+  vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
+  ASSERT_EQ (0, postdom_by_b.length ());
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+/* Verify that we can handle a CFG containing a "complete" aka
+   fully-connected subgraph (where A B C D below all have edges
+   pointing to each other node, also to themselves).
+   e.g.:
+     ENTRY  EXIT
+       |    ^
+       |   /
+       |  /
+       | /
+       V/
+       A<--->B
+       ^^   ^^
+       | \ / |
+       |  X  |
+       | / \ |
+       VV   VV
+       C<--->D
+*/
+
+static void
+test_fully_connected ()
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_fully_connected");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+
+  const int n = 4;
+
+  /* Create some empty blocks.  */
+  auto_vec <basic_block> subgraph_nodes;
+  for (int i = 0; i < n; i++)
+    subgraph_nodes.safe_push (create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun)));
+
+  ASSERT_EQ (n + 2, n_basic_blocks_for_fn (fun));
+  ASSERT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create the edges.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), subgraph_nodes[0], EDGE_FALLTHRU);
+  make_edge (subgraph_nodes[0], EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+  for (int i = 0; i < n; i++)
+    for (int j = 0; j < n; j++)
+      make_edge (subgraph_nodes[i], subgraph_nodes[j], 0);
+
+  /* Verify the edges.  */
+  ASSERT_EQ (2 + (n * n), n_edges_for_fn (fun));
+  /* The first one is linked to ENTRY/EXIT as well as itself and
+     everything else.  */
+  ASSERT_EQ (n + 1, subgraph_nodes[0]->preds->length ());
+  ASSERT_EQ (n + 1, subgraph_nodes[0]->succs->length ());
+  /* The other ones in the subgraph are linked to everything in
+     the subgraph (including themselves).  */
+  for (int i = 1; i < n; i++)
+    {
+      ASSERT_EQ (n, subgraph_nodes[i]->preds->length ());
+      ASSERT_EQ (n, subgraph_nodes[i]->succs->length ());
+    }
+
+  /* Verify the dominance information.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  /* The initial block in the subgraph should be dominated by ENTRY.  */
+  ASSERT_EQ (ENTRY_BLOCK_PTR_FOR_FN (fun),
+	     get_immediate_dominator (CDI_DOMINATORS,
+				      subgraph_nodes[0]));
+  /* Every other block in the subgraph should be dominated by the
+     initial block.  */
+  for (int i = 1; i < n; i++)
+    ASSERT_EQ (subgraph_nodes[0],
+	       get_immediate_dominator (CDI_DOMINATORS,
+					subgraph_nodes[i]));
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  /* The initial block in the subgraph should be postdominated by EXIT.  */
+  ASSERT_EQ (EXIT_BLOCK_PTR_FOR_FN (fun),
+	     get_immediate_dominator (CDI_POST_DOMINATORS,
+				      subgraph_nodes[0]));
+  /* Every other block in the subgraph should be postdominated by the
+     initial block, since that leads to EXIT.  */
+  for (int i = 1; i < n; i++)
+    ASSERT_EQ (subgraph_nodes[0],
+	       get_immediate_dominator (CDI_POST_DOMINATORS,
+					subgraph_nodes[i]));
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+tree_cfg_c_tests ()
+{
+  test_linear_chain ();
+  test_diamond ();
+  test_fully_connected ();
+}
+
+} // namespace selftest
+
+/* TODO: test the dominator/postdominator logic with various graphs/nodes:
+   - loop
+   - nested loops
+   - switch statement (a block with many out-edges)
+   - something that jumps to itself
+   - etc  */
+
+#endif /* CHECKING_P */
diff --git a/gcc/tree.c b/gcc/tree.c
index 2e01eac..fd0e692 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -61,6 +61,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "print-tree.h"
 #include "ipa-utils.h"
+#include "selftest.h"
 
 /* Tree code classes.  */
 
@@ -14203,4 +14204,65 @@ combined_fn_name (combined_fn fn)
     return internal_fn_name (as_internal_fn (fn));
 }
 
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests for tree.  */
+
+/* Verify that integer constants are sane.  */
+
+static void
+test_integer_constants ()
+{
+  ASSERT_TRUE (integer_type_node != NULL);
+  ASSERT_TRUE (build_int_cst (integer_type_node, 0) != NULL);
+
+  tree type = integer_type_node;
+
+  tree zero = build_zero_cst (type);
+  ASSERT_EQ (INTEGER_CST, TREE_CODE (zero));
+  ASSERT_EQ (type, TREE_TYPE (zero));
+
+  tree one = build_int_cst (type, 1);
+  ASSERT_EQ (INTEGER_CST, TREE_CODE (one));
+  ASSERT_EQ (type, TREE_TYPE (zero));
+}
+
+/* Verify identifiers.  */
+
+static void
+test_identifiers ()
+{
+  tree identifier = get_identifier ("foo");
+  ASSERT_EQ (3, IDENTIFIER_LENGTH (identifier));
+  ASSERT_STREQ ("foo", IDENTIFIER_POINTER (identifier));
+}
+
+/* Verify LABEL_DECL.  */
+
+static void
+test_labels ()
+{
+  tree identifier = get_identifier ("err");
+  tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
+				identifier, void_type_node);
+  ASSERT_EQ (-1, LABEL_DECL_UID (label_decl));
+  ASSERT_FALSE (FORCED_LABEL (label_decl));
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+tree_c_tests ()
+{
+  test_integer_constants ();
+  test_identifiers ();
+  test_labels ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
+
 #include "gt-tree.h"
diff --git a/gcc/vec.c b/gcc/vec.c
index a483d5b..fd200ea 100644
--- a/gcc/vec.c
+++ b/gcc/vec.c
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "hash-table.h"
+#include "selftest.h"
 
 /* vNULL is an empty type with a template cast operation that returns
    a zero-initialized vec<T, A, L> instance.  Use this when you want
@@ -188,3 +189,194 @@ dump_vec_loc_statistics (void)
 {
   vec_mem_desc.dump (VEC_ORIGIN);
 }
+
+#ifndef GENERATOR_FILE
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests.  */
+
+/* Call V.safe_push for all ints from START up to, but not including LIMIT.
+   Helper function for selftests.  */
+
+static void
+safe_push_range (vec <int>&v, int start, int limit)
+{
+  for (int i = start; i < limit; i++)
+    v.safe_push (i);
+}
+
+/* Verify that vec::quick_push works correctly.  */
+
+static void
+test_quick_push ()
+{
+  auto_vec <int> v;
+  ASSERT_EQ (0, v.length ());
+  v.reserve (3);
+  ASSERT_EQ (0, v.length ());
+  ASSERT_TRUE (v.space (3));
+  v.quick_push (5);
+  v.quick_push (6);
+  v.quick_push (7);
+  ASSERT_EQ (3, v.length ());
+  ASSERT_EQ (5, v[0]);
+  ASSERT_EQ (6, v[1]);
+  ASSERT_EQ (7, v[2]);
+}
+
+/* Verify that vec::safe_push works correctly.  */
+
+static void
+test_safe_push ()
+{
+  auto_vec <int> v;
+  ASSERT_EQ (0, v.length ());
+  v.safe_push (5);
+  v.safe_push (6);
+  v.safe_push (7);
+  ASSERT_EQ (3, v.length ());
+  ASSERT_EQ (5, v[0]);
+  ASSERT_EQ (6, v[1]);
+  ASSERT_EQ (7, v[2]);
+}
+
+/* Verify that vec::truncate works correctly.  */
+
+static void
+test_truncate ()
+{
+  auto_vec <int> v;
+  ASSERT_EQ (0, v.length ());
+  safe_push_range (v, 0, 10);
+  ASSERT_EQ (10, v.length ());
+
+  v.truncate (5);
+  ASSERT_EQ (5, v.length ());
+}
+
+/* Verify that vec::safe_grow_cleared works correctly.  */
+
+static void
+test_safe_grow_cleared ()
+{
+  auto_vec <int> v;
+  ASSERT_EQ (0, v.length ());
+  v.safe_grow_cleared (50);
+  ASSERT_EQ (50, v.length ());
+  ASSERT_EQ (0, v[0]);
+  ASSERT_EQ (0, v[49]);
+}
+
+/* Verify that vec::pop works correctly.  */
+
+static void
+test_pop ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 5, 20);
+  ASSERT_EQ (15, v.length ());
+
+  int last = v.pop ();
+  ASSERT_EQ (19, last);
+  ASSERT_EQ (14, v.length ());
+}
+
+/* Verify that vec::safe_insert works correctly.  */
+
+static void
+test_safe_insert ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.safe_insert (5, 42);
+  ASSERT_EQ (4, v[4]);
+  ASSERT_EQ (42, v[5]);
+  ASSERT_EQ (5, v[6]);
+  ASSERT_EQ (11, v.length ());
+}
+
+/* Verify that vec::ordered_remove works correctly.  */
+
+static void
+test_ordered_remove ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.ordered_remove (5);
+  ASSERT_EQ (4, v[4]);
+  ASSERT_EQ (6, v[5]);
+  ASSERT_EQ (9, v.length ());
+}
+
+/* Verify that vec::unordered_remove works correctly.  */
+
+static void
+test_unordered_remove ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.unordered_remove (5);
+  ASSERT_EQ (9, v.length ());
+}
+
+/* Verify that vec::block_remove works correctly.  */
+
+static void
+test_block_remove ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.block_remove (5, 3);
+  ASSERT_EQ (3, v[3]);
+  ASSERT_EQ (4, v[4]);
+  ASSERT_EQ (8, v[5]);
+  ASSERT_EQ (9, v[6]);
+  ASSERT_EQ (7, v.length ());
+}
+
+/* Comparator for use by test_qsort.  */
+
+static int
+reverse_cmp (const void *p_i, const void *p_j)
+{
+  return *(const int *)p_j - *(const int *)p_i;
+}
+
+/* Verify that vec::qsort works correctly.  */
+
+static void
+test_qsort ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.qsort (reverse_cmp);
+  ASSERT_EQ (9, v[0]);
+  ASSERT_EQ (8, v[1]);
+  ASSERT_EQ (1, v[8]);
+  ASSERT_EQ (0, v[9]);
+  ASSERT_EQ (10, v.length ());
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+vec_c_tests ()
+{
+  test_quick_push ();
+  test_safe_push ();
+  test_truncate ();
+  test_safe_grow_cleared ();
+  test_pop ();
+  test_safe_insert ();
+  test_ordered_remove ();
+  test_unordered_remove ();
+  test_block_remove ();
+  test_qsort ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
+#endif /* #ifndef GENERATOR_FILE */
diff --git a/gcc/wide-int.cc b/gcc/wide-int.cc
index 8648e7d..30d355f 100644
--- a/gcc/wide-int.cc
+++ b/gcc/wide-int.cc
@@ -23,6 +23,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
+#include "selftest.h"
+#include "wide-int-print.h"
 
 
 #define HOST_BITS_PER_HALF_WIDE_INT 32
@@ -2144,3 +2146,171 @@ template void generic_wide_int <wide_int_ref_storage <false> >::dump () const;
 template void generic_wide_int <wide_int_ref_storage <true> >::dump () const;
 template void offset_int::dump () const;
 template void widest_int::dump () const;
+
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests for wide ints.  We run these multiple times, once per type.  */
+
+/* Helper function for building a test value.  */
+
+template <class VALUE_TYPE>
+static VALUE_TYPE
+from_int (int i);
+
+/* Specializations of the fixture for each wide-int type.  */
+
+/* Specialization for VALUE_TYPE == wide_int.  */
+
+template <>
+wide_int
+from_int (int i)
+{
+  return wi::shwi (i, 32);
+}
+
+/* Specialization for VALUE_TYPE == offset_int.  */
+
+template <>
+offset_int
+from_int (int i)
+{
+  return offset_int (i);
+}
+
+/* Specialization for VALUE_TYPE == widest_int.  */
+
+template <>
+widest_int
+from_int (int i)
+{
+  return widest_int (i);
+}
+
+/* Verify that print_dec (WI, ..., SGN) gives the expected string
+   representation (using base 10).  */
+
+static void
+assert_deceq (const char *expected, const wide_int_ref &wi, signop sgn)
+{
+  char buf[WIDE_INT_PRINT_BUFFER_SIZE];
+  print_dec (wi, buf, sgn);
+  ASSERT_STREQ (expected, buf);
+}
+
+/* Likewise for base 16.  */
+
+static void
+assert_hexeq (const char *expected, const wide_int_ref &wi)
+{
+  char buf[WIDE_INT_PRINT_BUFFER_SIZE];
+  print_hex (wi, buf);
+  ASSERT_STREQ (expected, buf);
+}
+
+/* Test cases.  */
+
+/* Verify that print_dec and print_hex work for VALUE_TYPE.  */
+
+template <class VALUE_TYPE>
+static void
+test_printing ()
+{
+  VALUE_TYPE a = from_int<VALUE_TYPE> (42);
+  assert_deceq ("42", a, SIGNED);
+  assert_hexeq ("0x2a", a);
+}
+
+/* Verify that various operations work correctly for VALUE_TYPE,
+   unary and binary, using both function syntax, and
+   overloaded-operators.  */
+
+template <class VALUE_TYPE>
+static void
+test_ops ()
+{
+  VALUE_TYPE a = from_int<VALUE_TYPE> (7);
+  VALUE_TYPE b = from_int<VALUE_TYPE> (3);
+
+  /* Using functions.  */
+  assert_deceq ("-7", wi::neg (a), SIGNED);
+  assert_deceq ("10", wi::add (a, b), SIGNED);
+  assert_deceq ("4", wi::sub (a, b), SIGNED);
+  assert_deceq ("-4", wi::sub (b, a), SIGNED);
+  assert_deceq ("21", wi::mul (a, b), SIGNED);
+
+  /* Using operators.  */
+  assert_deceq ("-7", -a, SIGNED);
+  assert_deceq ("10", a + b, SIGNED);
+  assert_deceq ("4", a - b, SIGNED);
+  assert_deceq ("-4", b - a, SIGNED);
+  assert_deceq ("21", a * b, SIGNED);
+}
+
+/* Verify that various comparisons work correctly for VALUE_TYPE.  */
+
+template <class VALUE_TYPE>
+static void
+test_comparisons ()
+{
+  VALUE_TYPE a = from_int<VALUE_TYPE> (7);
+  VALUE_TYPE b = from_int<VALUE_TYPE> (3);
+
+  /* == */
+  ASSERT_TRUE (wi::eq_p (a, a));
+  ASSERT_FALSE (wi::eq_p (a, b));
+
+  /* != */
+  ASSERT_TRUE (wi::ne_p (a, b));
+  ASSERT_FALSE (wi::ne_p (a, a));
+
+  /* < */
+  ASSERT_FALSE (wi::lts_p (a, a));
+  ASSERT_FALSE (wi::lts_p (a, b));
+  ASSERT_TRUE (wi::lts_p (b, a));
+
+  /* <= */
+  ASSERT_TRUE (wi::les_p (a, a));
+  ASSERT_FALSE (wi::les_p (a, b));
+  ASSERT_TRUE (wi::les_p (b, a));
+
+  /* > */
+  ASSERT_FALSE (wi::gts_p (a, a));
+  ASSERT_TRUE (wi::gts_p (a, b));
+  ASSERT_FALSE (wi::gts_p (b, a));
+
+  /* >= */
+  ASSERT_TRUE (wi::ges_p (a, a));
+  ASSERT_TRUE (wi::ges_p (a, b));
+  ASSERT_FALSE (wi::ges_p (b, a));
+
+  /* comparison */
+  ASSERT_EQ (-1, wi::cmps (b, a));
+  ASSERT_EQ (0, wi::cmps (a, a));
+  ASSERT_EQ (1, wi::cmps (a, b));
+}
+
+/* Run all of the selftests, using the given VALUE_TYPE.  */
+
+template <class VALUE_TYPE>
+static void run_all_wide_int_tests ()
+{
+  test_printing <VALUE_TYPE> ();
+  test_ops <VALUE_TYPE> ();
+  test_comparisons <VALUE_TYPE> ();
+}
+
+/* Run all of the selftests within this file, for all value types.  */
+
+void
+wide_int_cc_tests ()
+{
+ run_all_wide_int_tests <wide_int> ();
+ run_all_wide_int_tests <offset_int> ();
+ run_all_wide_int_tests <widest_int> ();
+}
+
+} // namespace selftest
+#endif /* CHECKING_P */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH] Selftest framework (v7)
  2016-06-06 14:17                                         ` David Malcolm
  2016-06-06 14:41                                           ` Bernd Schmidt
@ 2016-06-06 21:47                                           ` Trevor Saunders
  2016-06-06 21:57                                             ` Jakub Jelinek
  1 sibling, 1 reply; 176+ messages in thread
From: Trevor Saunders @ 2016-06-06 21:47 UTC (permalink / raw)
  To: David Malcolm; +Cc: Bernd Schmidt, gcc-patches, Bernd Schmidt, Jeff Law

> > As far as I can 
> > tell this just involves moving the start of namespace selftest
> > upwards a 
> > bit in the files where we have tests.
> 
> Yes, and it does seem cleaner to have all of the selftest code start
> like this:
> 
>   #if CHECKING_P

What are we gaining by ifdefing this? I would think on reasonable
systems the compiler would optimize out the call to the selftests in
release builds and then the linker would gc all the unused functions.
Do we really care about code size in places that doesn't happen enough
to go through this?

Thanks!

Trev

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH] Selftest framework (v7)
  2016-06-06 21:47                                           ` [PATCH] Selftest framework (v7) Trevor Saunders
@ 2016-06-06 21:57                                             ` Jakub Jelinek
  2016-06-07  2:07                                               ` Trevor Saunders
  0 siblings, 1 reply; 176+ messages in thread
From: Jakub Jelinek @ 2016-06-06 21:57 UTC (permalink / raw)
  To: Trevor Saunders
  Cc: David Malcolm, Bernd Schmidt, gcc-patches, Bernd Schmidt, Jeff Law

On Mon, Jun 06, 2016 at 05:53:50PM -0400, Trevor Saunders wrote:
> > > As far as I can 
> > > tell this just involves moving the start of namespace selftest
> > > upwards a 
> > > bit in the files where we have tests.
> > 
> > Yes, and it does seem cleaner to have all of the selftest code start
> > like this:
> > 
> >   #if CHECKING_P
> 
> What are we gaining by ifdefing this? I would think on reasonable
> systems the compiler would optimize out the call to the selftests in
> release builds and then the linker would gc all the unused functions.
> Do we really care about code size in places that doesn't happen enough
> to go through this?

Not everyone is building the compiler with LTO, and if you don't, then
how would you optimize that away?
And yes, not having the self-tests, especially if they are going to grow
further, in release compilers is desirable, especially if it would be
intermixed with hot code.

	Jakub

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH] Selftest framework (v7)
  2016-06-06 21:57                                             ` Jakub Jelinek
@ 2016-06-07  2:07                                               ` Trevor Saunders
  2016-06-07 14:18                                                 ` David Malcolm
  0 siblings, 1 reply; 176+ messages in thread
From: Trevor Saunders @ 2016-06-07  2:07 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: David Malcolm, Bernd Schmidt, gcc-patches, Bernd Schmidt, Jeff Law

On Mon, Jun 06, 2016 at 11:57:49PM +0200, Jakub Jelinek wrote:
> On Mon, Jun 06, 2016 at 05:53:50PM -0400, Trevor Saunders wrote:
> > > > As far as I can 
> > > > tell this just involves moving the start of namespace selftest
> > > > upwards a 
> > > > bit in the files where we have tests.
> > > 
> > > Yes, and it does seem cleaner to have all of the selftest code start
> > > like this:
> > > 
> > >   #if CHECKING_P
> > 
> > What are we gaining by ifdefing this? I would think on reasonable
> > systems the compiler would optimize out the call to the selftests in
> > release builds and then the linker would gc all the unused functions.
> > Do we really care about code size in places that doesn't happen enough
> > to go through this?
> 
> Not everyone is building the compiler with LTO, and if you don't, then
> how would you optimize that away?

-ffunction-sections -Wl,--gc-sections should be enough I think.  I guess
we don't use those at the moment though.

> And yes, not having the self-tests, especially if they are going to grow
> further, in release compilers is desirable, especially if it would be
> intermixed with hot code.

That's fair, though turning on --gc-sections where we can should further
help with that, and that should be more effective with
-ffunction-sections -fdata-sections, so its seems to me like the right
thing to do is add configure tests to enable those?  And then its more
of a non issue?

Trev

> 
> 	Jakub

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH] Selftest framework (v7)
  2016-06-07  2:07                                               ` Trevor Saunders
@ 2016-06-07 14:18                                                 ` David Malcolm
  2016-06-08  0:23                                                   ` Trevor Saunders
  0 siblings, 1 reply; 176+ messages in thread
From: David Malcolm @ 2016-06-07 14:18 UTC (permalink / raw)
  To: Trevor Saunders, Jakub Jelinek
  Cc: Bernd Schmidt, gcc-patches, Bernd Schmidt, Jeff Law

On Mon, 2016-06-06 at 22:14 -0400, Trevor Saunders wrote:
> On Mon, Jun 06, 2016 at 11:57:49PM +0200, Jakub Jelinek wrote:
> > On Mon, Jun 06, 2016 at 05:53:50PM -0400, Trevor Saunders wrote:
> > > > > As far as I can 
> > > > > tell this just involves moving the start of namespace
> > > > > selftest
> > > > > upwards a 
> > > > > bit in the files where we have tests.
> > > > 
> > > > Yes, and it does seem cleaner to have all of the selftest code
> > > > start
> > > > like this:
> > > > 
> > > >   #if CHECKING_P
> > > 
> > > What are we gaining by ifdefing this? I would think on reasonable
> > > systems the compiler would optimize out the call to the selftests
> > > in
> > > release builds and then the linker would gc all the unused
> > > functions.
> > > Do we really care about code size in places that doesn't happen
> > > enough
> > > to go through this?
> > 
> > Not everyone is building the compiler with LTO, and if you don't,
> > then
> > how would you optimize that away?
> 
> -ffunction-sections -Wl,--gc-sections should be enough I think.  I
> guess
> we don't use those at the moment though.
> 
> > And yes, not having the self-tests, especially if they are going to
> > grow
> > further, in release compilers is desirable, especially if it would
> > be
> > intermixed with hot code.
> 
> That's fair, though turning on --gc-sections where we can should
> further
> help with that, and that should be more effective with
> -ffunction-sections -fdata-sections, so its seems to me like the
> right
> thing to do is add configure tests to enable those?  And then its
> more
> of a non issue?

I appreciate that you'd done a lot of work on eliminating preprocessor
use in gcc, and that we'd prefer to minimize the amount of #if code we
have - though it's relatively easy to test the with/without #if
CHECKING_P case (compared to all of the various target-specific
macros).

Historically gcc testing has largely been "black box" testing: run the
built programs with specific inputs and look for specific outputs. My
hope with -fself-tests is that we can build up our "white box" test
coverage to complement the above, with unit tests.  My favorite example
is the testing for gengtype that I posted as a followup, which gives us
some immediate test coverage that gengtype is working as expected,
which is hard to do using our traditional approach to testing.

I hope that we can add a lot more tests to -fself-test, in particular,
I want us to have unit tests for hot code, including code that's hidden
deep inside the implementation and that might normally get inlined
away.  To play Devil's Advocate: if we find we're able to do a release
build with the selftests enabled and that it isn't slowing down the
release build, does that imply we need more unit tests for our hottest
code?  (the counterargument being that the checked build still needs to
run in a bearable amount of time).

That said, I want -fself-test to always run quickly (e.g. less than a
second); let's not put anything slow in there.  Also, any unit tests
involving analyzing several gimple or RTL statements at once seem to be
easier to do via the gimple and RTL frontends that Prasad and I are
working on respectively.  (I think we can use -fself-test for unit
-testing implementation details of passes that involve one statement at
a time, but as soon as we start dealing with multiple statements and
control flow, that it's probably better to express it using a
gimple/RTL dump in DejaGnu form).


Hope the above sounds sane
Dave

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [PATCH] Selftest framework (v7)
  2016-06-07 14:18                                                 ` David Malcolm
@ 2016-06-08  0:23                                                   ` Trevor Saunders
  0 siblings, 0 replies; 176+ messages in thread
From: Trevor Saunders @ 2016-06-08  0:23 UTC (permalink / raw)
  To: David Malcolm
  Cc: Jakub Jelinek, Bernd Schmidt, gcc-patches, Bernd Schmidt, Jeff Law

On Tue, Jun 07, 2016 at 10:18:32AM -0400, David Malcolm wrote:
> On Mon, 2016-06-06 at 22:14 -0400, Trevor Saunders wrote:
> > On Mon, Jun 06, 2016 at 11:57:49PM +0200, Jakub Jelinek wrote:
> > > On Mon, Jun 06, 2016 at 05:53:50PM -0400, Trevor Saunders wrote:
> > > > > > As far as I can 
> > > > > > tell this just involves moving the start of namespace
> > > > > > selftest
> > > > > > upwards a 
> > > > > > bit in the files where we have tests.
> > > > > 
> > > > > Yes, and it does seem cleaner to have all of the selftest code
> > > > > start
> > > > > like this:
> > > > > 
> > > > >   #if CHECKING_P
> > > > 
> > > > What are we gaining by ifdefing this? I would think on reasonable
> > > > systems the compiler would optimize out the call to the selftests
> > > > in
> > > > release builds and then the linker would gc all the unused
> > > > functions.
> > > > Do we really care about code size in places that doesn't happen
> > > > enough
> > > > to go through this?
> > > 
> > > Not everyone is building the compiler with LTO, and if you don't,
> > > then
> > > how would you optimize that away?
> > 
> > -ffunction-sections -Wl,--gc-sections should be enough I think.  I
> > guess
> > we don't use those at the moment though.
> > 
> > > And yes, not having the self-tests, especially if they are going to
> > > grow
> > > further, in release compilers is desirable, especially if it would
> > > be
> > > intermixed with hot code.
> > 
> > That's fair, though turning on --gc-sections where we can should
> > further
> > help with that, and that should be more effective with
> > -ffunction-sections -fdata-sections, so its seems to me like the
> > right
> > thing to do is add configure tests to enable those?  And then its
> > more
> > of a non issue?
> 
> I appreciate that you'd done a lot of work on eliminating preprocessor
> use in gcc, and that we'd prefer to minimize the amount of #if code we
> have - though it's relatively easy to test the with/without #if
> CHECKING_P case (compared to all of the various target-specific
> macros).

yeah, I certainly agree CHECKING_P is one of the more defensable macros.

> Historically gcc testing has largely been "black box" testing: run the
> built programs with specific inputs and look for specific outputs. My
> hope with -fself-tests is that we can build up our "white box" test
> coverage to complement the above, with unit tests.  My favorite example
> is the testing for gengtype that I posted as a followup, which gives us
> some immediate test coverage that gengtype is working as expected,
> which is hard to do using our traditional approach to testing.

I'd probably say testing hash tables / vec is more useful, but whatever
;)

> I hope that we can add a lot more tests to -fself-test, in particular,
> I want us to have unit tests for hot code, including code that's hidden
> deep inside the implementation and that might normally get inlined
> away.  To play Devil's Advocate: if we find we're able to do a release
> build with the selftests enabled and that it isn't slowing down the
> release build, does that imply we need more unit tests for our hottest
> code?  (the counterargument being that the checked build still needs to
> run in a bearable amount of time).

by enabled do you mean we build the code or actually run the tests on
every compile?  I would think basically any tests are two slow for the
latter.  For the former I would say building the self test code should
have very little effect on performance since its all separate functions.
There's some of course because of call sites effecting inlining etc, but
we can probably minimize that with -ffunction-sections --gc-sections and
attribute cold?

> That said, I want -fself-test to always run quickly (e.g. less than a
> second); let's not put anything slow in there.  Also, any unit tests
> involving analyzing several gimple or RTL statements at once seem to be
> easier to do via the gimple and RTL frontends that Prasad and I are
> working on respectively.  (I think we can use -fself-test for unit
> -testing implementation details of passes that involve one statement at
> a time, but as soon as we start dealing with multiple statements and
> control flow, that it's probably better to express it using a
> gimple/RTL dump in DejaGnu form).

That makes sense.

Trev

> 
> 
> Hope the above sounds sane
> Dave

^ permalink raw reply	[flat|nested] 176+ messages in thread

end of thread, other threads:[~2016-06-08  0:23 UTC | newest]

Thread overview: 176+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-10 15:10 [PATCH 00/17] RFC: Addding a unit testing framework to gcc David Malcolm
2015-06-10 15:10 ` [PATCH 09/17] Add test-hash-set.c to gcc/unittests David Malcolm
2015-06-10 15:10 ` [PATCH 01/17] Add Make-lang.in and config-lang.in " David Malcolm
2015-06-10 15:10 ` [PATCH 02/17] Add test-bitmap.c " David Malcolm
2015-06-23 19:17   ` Jeff Law
2015-06-10 15:10 ` [PATCH 11/17] Add test-rtl.c " David Malcolm
2015-06-10 15:10 ` [PATCH 04/17] Add test-folding.c " David Malcolm
2015-06-10 15:10 ` [PATCH 10/17] Add test-locations.c " David Malcolm
2015-06-10 15:10 ` [PATCH 05/17] Add test-functions.c " David Malcolm
2015-06-10 15:10 ` [PATCH 08/17] Add test-hash-map.c " David Malcolm
2015-06-10 15:10 ` [PATCH 12/17] Add test-tree.c " David Malcolm
2015-06-10 15:10 ` [PATCH 07/17] Add test-gimple.c " David Malcolm
2015-06-10 15:17 ` [PATCH 03/17] Add test-cfg.c " David Malcolm
2015-06-23 19:26   ` Jeff Law
2015-06-25 18:13     ` David Malcolm
2015-06-10 15:25 ` [PATCH 17/17] toplev.c: move location_adhoc_data_fini call David Malcolm
2015-06-10 15:26 ` [PATCH 13/17] Add test-vec.c to gcc/unittests David Malcolm
2015-06-10 15:26 ` [PATCH 16/17] Add unittests-main.c " David Malcolm
2015-06-10 15:28 ` [PATCH 15/17] Add unittests-frontend.c " David Malcolm
2015-06-10 15:28 ` [PATCH 06/17] Add test-ggc.c " David Malcolm
2015-06-10 15:34 ` [PATCH 14/17] Add test-wide-int.c " David Malcolm
2015-06-10 16:19 ` [PATCH 00/17] RFC: Addding a unit testing framework to gcc Jakub Jelinek
2015-06-10 16:25   ` Richard Biener
2015-06-10 17:56   ` David Malcolm
2015-06-10 23:42     ` Jakub Jelinek
2015-06-17 20:36       ` [PATCH/RFC]: unittesting v2: as a plugin (was Re: [PATCH 00/17] RFC: Addding a unit testing framework to gcc) David Malcolm
2015-06-23 19:29         ` Jeff Law
2015-10-27 19:31           ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
2015-10-27 19:31             ` [PATCH 11/16] Add test-hash-set.c to unittests David Malcolm
2015-10-30  4:54               ` Jeff Law
2015-10-27 19:31             ` [PATCH 05/16] Add test-et-forest.c " David Malcolm
2015-10-30  4:11               ` Jeff Law
2015-10-27 19:31             ` [PATCH 15/16] Add test-vec.c " David Malcolm
2015-10-30  5:10               ` Jeff Law
2015-10-27 19:31             ` [PATCH 03/16] Add test-bitmap.c " David Malcolm
2015-10-29 21:36               ` Jeff Law
2015-10-27 19:31             ` [PATCH 01/16] Add unittest infrastructure David Malcolm
2015-10-30  5:20               ` Jeff Law
2015-10-27 19:32             ` [PATCH 04/16] Add test-cfg.c to unittests David Malcolm
2015-10-29 22:23               ` Jeff Law
2015-10-27 19:32             ` [PATCH 10/16] Add test-hash-map.c " David Malcolm
2015-10-30  4:57               ` Jeff Law
2015-10-27 19:32             ` [PATCH 07/16] Add test-functions.c " David Malcolm
2015-10-30  5:19               ` Jeff Law
2015-10-27 19:35             ` [PATCH 06/16] Add test-folding.c " David Malcolm
2015-10-30  5:06               ` Jeff Law
2015-10-27 19:48             ` [PATCH 14/16] Add test-tree.c " David Malcolm
2015-10-30  5:00               ` Jeff Law
2015-10-27 19:49             ` [PATCH 08/16] Add test-ggc.c " David Malcolm
2015-10-30  5:08               ` Jeff Law
2015-10-27 19:49             ` [PATCH 12/16] Add test-locations.c " David Malcolm
2015-10-30  5:09               ` Jeff Law
2015-10-27 19:50             ` [PATCH 13/16] Add test-rtl.c " David Malcolm
2015-10-30  4:58               ` Jeff Law
2015-10-31 20:36                 ` Segher Boessenkool
2015-10-27 19:51             ` [PATCH 16/16] Add test-wide-int.c " David Malcolm
2015-10-30  5:15               ` Jeff Law
2015-10-27 19:58             ` [PATCH 09/16] Add test-gimple.c " David Malcolm
2015-10-28 12:39               ` Richard Biener
2015-10-28 12:44                 ` Richard Biener
2015-10-28 16:22                   ` Jeff Law
2015-10-30  5:02               ` Jeff Law
2015-10-27 20:16             ` [PATCH 00/16] Unit tests framework (v3) David Malcolm
2015-10-30  5:28               ` Jeff Law
2015-10-28 11:53             ` Bernd Schmidt
2015-10-28 13:02               ` Bernd Schmidt
2015-10-29 16:20               ` David Malcolm
2015-10-29 19:38                 ` Jeff Law
2015-10-29 22:32                   ` Mike Stump
2015-10-30  3:59                     ` Jeff Law
2015-10-29 19:21               ` Jeff Law
2015-10-30 10:54                 ` Bernd Schmidt
2015-10-30 16:08                   ` Jeff Law
2015-11-16 18:17                     ` Bernd Schmidt
2015-11-16 18:48                       ` David Malcolm
2015-11-16 21:22                         ` Bernd Schmidt
2015-11-16 23:12                         ` Jeff Law
2015-11-17  1:54                           ` Mike Stump
2015-11-17 12:51                             ` Bernd Schmidt
2015-11-17 18:06                               ` Jeff Law
2015-11-19 16:46                       ` [PATCH 00/15] Unittests framework v4: -fself-test David Malcolm
2015-11-19 16:46                         ` [PATCH 07/15] Fix warning in function-tests.c David Malcolm
2015-11-19 16:46                         ` [PATCH 03/15] Add selftests to tree-cfg.c David Malcolm
2015-11-19 16:46                         ` [PATCH 08/15] Add selftests to gimple.c David Malcolm
2015-11-19 16:46                         ` [PATCH 02/15] Add selftests to bitmap.c David Malcolm
2015-11-20 10:41                           ` Richard Biener
2015-11-24 21:13                           ` Jeff Law
2015-11-19 16:46                         ` [PATCH 05/15] Add selftests to fold-const.c David Malcolm
2015-11-19 16:46                         ` [PATCH 09/15] Add hash-map-tests.c David Malcolm
2015-11-19 16:46                         ` [PATCH 10/15] Add hash-set-tests.c David Malcolm
2015-11-19 16:46                         ` [PATCH 06/15] Add function-tests.c David Malcolm
2015-11-19 16:46                         ` [PATCH 13/15] Add selftests to tree.c David Malcolm
2015-11-19 16:46                         ` [PATCH 14/15] Add selftests to vec.c David Malcolm
2015-11-19 16:46                         ` [PATCH 01/15] Selftest framework (unittests v4) David Malcolm
2015-11-19 17:35                           ` Bernd Schmidt
2015-11-19 18:08                             ` David Malcolm
2015-11-19 18:15                               ` Mike Stump
2015-11-19 18:44                               ` Bernd Schmidt
2015-11-19 20:04                                 ` Mikhail Maltsev
2015-11-24 20:45                                 ` Jeff Law
2015-11-25  2:43                                   ` David Malcolm
2015-11-25 10:56                                     ` Bernd Schmidt
2015-11-25 16:57                                       ` Mike Stump
2015-11-29 18:10                                         ` Jeff Law
2015-11-25 22:58                                       ` David Malcolm
2015-11-25  7:43                                   ` Trevor Saunders
2015-11-25 22:53                                 ` David Malcolm
2015-11-26 13:00                                   ` Bernd Schmidt
2015-11-30 23:05                                     ` Jeff Law
2015-11-24 20:29                             ` Jeff Law
2015-11-24 22:43                           ` Jeff Law
2015-11-19 16:46                         ` [PATCH 04/15] Add selftests to et-forest.c David Malcolm
2015-11-19 16:46                         ` [PATCH 15/15] RFC: Add ggc-tests.c David Malcolm
2015-11-19 17:03                         ` [PATCH 12/15] Add rtl-tests.c David Malcolm
2015-11-19 17:03                         ` [PATCH 11/15] Add selftests to input.c David Malcolm
2016-06-01 20:54                         ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) David Malcolm
2016-06-01 20:54                           ` [PATCH 07/21] Add selftests to bitmap.c David Malcolm
2016-06-01 20:54                           ` [PATCH 04/21] Add -fself-test-regex= David Malcolm
2016-06-01 20:54                           ` [PATCH 09/21] Add selftests to et-forest.c David Malcolm
2016-06-01 20:54                           ` [PATCH 03/21] Various selftest::runner tweaks David Malcolm
2016-06-01 20:54                           ` [PATCH 02/21] Makefile.in integration David Malcolm
2016-06-01 20:54                           ` [PATCH 17/21] Add hash-set-tests.c David Malcolm
2016-06-01 20:54                           ` [PATCH 20/21] Add selftests to tree.c David Malcolm
2016-06-01 20:54                           ` [PATCH 18/21] Add selftests to input.c David Malcolm
2016-06-01 20:54                           ` [PATCH 01/21] Selftest framework (unittests v5) David Malcolm
2016-06-01 20:54                           ` [PATCH 10/21] Add selftests to fold-const.c David Malcolm
2016-06-01 21:09                           ` [PATCH 12/21] Fix warning in function-tests.c David Malcolm
2016-06-01 21:10                           ` [PATCH 21/21] Add selftests to vec.c David Malcolm
2016-06-01 21:10                           ` [PATCH 06/21] Convert Levenshtein test from a plugin to a selftest David Malcolm
2016-06-01 21:10                           ` [PATCH 08/21] Add selftests to tree-cfg.c David Malcolm
2016-06-01 21:10                           ` [PATCH 11/21] Add function-tests.c David Malcolm
2016-06-01 21:11                           ` [PATCH 16/21] Add hash-map-tests.c David Malcolm
2016-06-01 21:20                           ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) Sandra Loosemore
2016-06-02 13:08                             ` David Malcolm
2016-06-01 21:21                           ` [PATCH 05/21] Add selftests for diagnostic-show-locus.c David Malcolm
2016-06-01 21:22                           ` [PATCH 19/21] Add rtl-tests.c David Malcolm
2016-06-01 21:23                           ` [PATCH 15/21] Add selftests to gimple.c David Malcolm
2016-06-01 21:26                           ` [PATCH 14/21] Remove x86_64-isms in function-tests.c David Malcolm
2016-06-01 21:29                           ` [PATCH 13/21] Fixup to function-tests.c David Malcolm
2016-06-02 10:30                           ` [PATCH 00/21] Add -fself-test framework for fast, early unit-testing (unittests v5) Bernd Schmidt
2016-06-02 13:41                             ` David Malcolm
2016-06-02 20:41                               ` [PATCH 00/16] v6 of -fself-test/unit-testing patch David Malcolm
2016-06-02 20:41                                 ` [PATCH 01/16] Core of selftest framework (v6) David Malcolm
2016-06-02 23:21                                   ` Bernd Schmidt
2016-06-03 18:47                                     ` [PATCH] Selftest framework (v7) David Malcolm
2016-06-05 11:38                                       ` Bernd Schmidt
2016-06-06 14:17                                         ` David Malcolm
2016-06-06 14:41                                           ` Bernd Schmidt
2016-06-06 17:18                                             ` [Committed] Selftest framework (v8) David Malcolm
2016-06-06 21:47                                           ` [PATCH] Selftest framework (v7) Trevor Saunders
2016-06-06 21:57                                             ` Jakub Jelinek
2016-06-07  2:07                                               ` Trevor Saunders
2016-06-07 14:18                                                 ` David Malcolm
2016-06-08  0:23                                                   ` Trevor Saunders
2016-06-02 20:41                                 ` [PATCH 10/16] Add hash-map-tests.c David Malcolm
2016-06-02 20:41                                 ` [PATCH 03/16] spellcheck.c: convert Levenshtein test from a plugin to a selftest David Malcolm
2016-06-02 20:41                                 ` [PATCH 02/16] diagnostic-show-locus.c: add selftests David Malcolm
2016-06-02 20:41                                 ` [PATCH 09/16] gimple.c: " David Malcolm
2016-06-02 20:41                                 ` [PATCH 05/16] tree-cfg.c: " David Malcolm
2016-06-02 20:41                                 ` [PATCH 04/16] bitmap.c: " David Malcolm
2016-06-02 20:57                                 ` [PATCH 08/16] Add function-tests.c David Malcolm
2016-06-02 20:58                                 ` [PATCH 14/16] tree.c: add selftests David Malcolm
2016-06-02 21:03                                 ` [PATCH 12/16] input.c: " David Malcolm
2016-06-02 21:03                                 ` [PATCH 13/16] Add rtl-tests.c David Malcolm
2016-06-02 21:03                                 ` [PATCH 16/16] wide-int.cc: add selftests David Malcolm
2016-06-02 21:06                                 ` [PATCH 15/16] vec.c: " David Malcolm
2016-06-02 21:09                                 ` [PATCH 07/16] fold-const.c: " David Malcolm
2016-06-02 21:09                                 ` [PATCH 11/16] Add hash-set-tests.c David Malcolm
2016-06-02 21:09                                 ` [PATCH 06/16] et-forest.c: add selftests David Malcolm
2015-10-28 16:05             ` [PATCH 00/16] Unit tests framework (v3) Jeff Law
2015-10-28 20:26             ` Mike Stump
2015-06-23 19:06     ` [PATCH 00/17] RFC: Addding a unit testing framework to gcc Jeff Law
2015-06-23 20:04     ` Mike Stump
2015-06-10 18:21   ` David Malcolm
2015-06-10 22:15     ` Jakub Jelinek
2015-06-11 14:49 ` Martin Liška

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).