diff mbox

Selftest framework (v7)

Message ID 1464981166-25871-1-git-send-email-dmalcolm@redhat.com
State New
Headers show

Commit Message

David Malcolm June 3, 2016, 7:12 p.m. UTC
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

Comments

Bernd Schmidt June 5, 2016, 11:37 a.m. UTC | #1
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
David Malcolm June 6, 2016, 2:17 p.m. UTC | #2
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
Bernd Schmidt June 6, 2016, 2:40 p.m. UTC | #3
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
Trevor Saunders June 6, 2016, 9:53 p.m. UTC | #4
> > 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
Jakub Jelinek June 6, 2016, 9:57 p.m. UTC | #5
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
Trevor Saunders June 7, 2016, 2:14 a.m. UTC | #6
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
David Malcolm June 7, 2016, 2:18 p.m. UTC | #7
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
Trevor Saunders June 8, 2016, 12:28 a.m. UTC | #8
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
diff mbox

Patch

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 */