Selftest framework
authorDavid Malcolm <dmalcolm@redhat.com>
Mon, 6 Jun 2016 17:11:30 +0000 (17:11 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Mon, 6 Jun 2016 17:11:30 +0000 (17:11 +0000)
gcc/ChangeLog:
* Makefile.in (OBJS): Add function-tests.o,
hash-map-tests.o, hash-set-tests.o, rtl-tests.o,
selftest-run-tests.o.
(OBJS-libcommon): Add selftest.o.
(OBJS-libcommon-target): Add selftest.o.
(all.internal): Add "selftest".
(all.cross): Likewise.
(selftest): New phony target.
(s-selftest): New target.
(selftest-gdb): New phony target.
(COLLECT2_OBJS): Add selftest.o.
* bitmap.c: Include "selftest.h".
(selftest::test_gc_alloc): New function.
(selftest::test_set_range): New function.
(selftest::test_clear_bit_in_middle): New function.
(selftest::test_copying): New function.
(selftest::test_bitmap_single_bit_set_p): New function.
(selftest::bitmap_c_tests): New function.
* common.opt (fself-test): New.
* diagnostic-show-locus.c: Include "selftest.h".
(make_range): New function.
(test_range_contains_point_for_single_point): New function.
(test_range_contains_point_for_single_line): New function.
(test_range_contains_point_for_multiple_lines): New function.
(assert_eq): New function.
(test_get_line_width_without_trailing_whitespace): New function.
(selftest::diagnostic_show_locus_c_tests): New function.
* et-forest.c: Include "selftest.h".
(selftest::test_single_node): New function.
(selftest::test_simple_tree): New function.
(selftest::test_disconnected_nodes): New function.
(selftest::et_forest_c_tests): New function.
* fold-const.c: Include "selftest.h".
(selftest::assert_binop_folds_to_const): New function.
(selftest::assert_binop_folds_to_nonlvalue): New function.
(selftest::test_arithmetic_folding): New function.
(selftest::fold_const_c_tests): New function.
* function-tests.c: New file.
* gimple.c: Include "selftest.h".
Include "gimple-pretty-print.h".
(selftest::verify_gimple_pp): New function.
(selftest::test_assign_single): New function.
(selftest::test_assign_binop): New function.
(selftest::test_nop_stmt): New function.
(selftest::test_return_stmt): New function.
(selftest::test_return_without_value): New function.
(selftest::gimple_c_tests): New function.
* hash-map-tests.c: New file.
* hash-set-tests.c: New file.
* input.c: Include "selftest.h".
(selftest::assert_loceq): New function.
(selftest::test_accessing_ordinary_linemaps): New function.
(selftest::test_unknown_location): New function.
(selftest::test_builtins): New function.
(selftest::test_reading_source_line): New function.
(selftest::input_c_tests): New function.
* rtl-tests.c: New file.
* selftest-run-tests.c: New file.
* selftest.c: New file.
* selftest.h: New file.
* spellcheck.c: Include "selftest.h".
(selftest::levenshtein_distance_unit_test_oneway): New function,
adapted from testsuite/gcc.dg/plugin/levenshtein_plugin.c.
(selftest::levenshtein_distance_unit_test): Likewise.
(selftest::spellcheck_c_tests): Likewise.
* toplev.c: Include selftest.h.
(toplev::run_self_tests): New.
(toplev::main): Handle -fself-test.
* toplev.h (toplev::run_self_tests): New.
* tree.c: Include "selftest.h".
(selftest::test_integer_constants): New function.
(selftest::test_identifiers): New function.
(selftest::test_labels): New function.
(selftest::tree_c_tests): New function.
* tree-cfg.c: Include "selftest.h".
(selftest::push_fndecl): New function.
(selftest::test_linear_chain): New function.
(selftest::test_diamond): New function.
(selftest::test_fully_connected): New function.
(selftest::tree_cfg_c_tests): New function.
* vec.c: Include "selftest.h".
(selftest::safe_push_range): New function.
(selftest::test_quick_push): New function.
(selftest::test_safe_push): New function.
(selftest::test_truncate): New function.
(selftest::test_safe_grow_cleared): New function.
(selftest::test_pop): New function.
(selftest::test_safe_insert): New function.
(selftest::test_ordered_remove): New function.
(selftest::test_unordered_remove): New function.
(selftest::test_block_remove): New function.
(selftest::reverse_cmp): New function.
(selftest::test_qsort): New function.
(selftest::vec_c_tests): New function.c.
* wide-int.cc: Include selftest.h and wide-int-print.h.
(selftest::from_int <wide_int>): New function.
(selftest::from_int <offset_int>): New function.
(selftest::from_int <widest_int>): New function.
(selftest::assert_deceq): New function.
(selftest::assert_hexeq): New function.
(selftest::test_printing <VALUE_TYPE>): New function template.
(selftest::test_ops <VALUE_TYPE>): New function template.
(selftest::test_comparisons <VALUE_TYPE>): New function template.
(selftest::run_all_wide_int_tests <VALUE_TYPE>): New function
template.
(selftest::wide_int_cc_tests): New function.

gcc/testsuite/ChangeLog:
* gcc.dg/plugin/levenshtein-test-1.c: Delete.
* gcc.dg/plugin/levenshtein_plugin.c: Delete.
* gcc.dg/plugin/plugin.exp (plugin_test_list): Remove the
above.

From-SVN: r237144

27 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/bitmap.c
gcc/common.opt
gcc/diagnostic-show-locus.c
gcc/et-forest.c
gcc/fold-const.c
gcc/function-tests.c [new file with mode: 0644]
gcc/gimple.c
gcc/hash-map-tests.c [new file with mode: 0644]
gcc/hash-set-tests.c [new file with mode: 0644]
gcc/input.c
gcc/rtl-tests.c [new file with mode: 0644]
gcc/selftest-run-tests.c [new file with mode: 0644]
gcc/selftest.c [new file with mode: 0644]
gcc/selftest.h [new file with mode: 0644]
gcc/spellcheck.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/plugin/levenshtein-test-1.c [deleted file]
gcc/testsuite/gcc.dg/plugin/levenshtein_plugin.c [deleted file]
gcc/testsuite/gcc.dg/plugin/plugin.exp
gcc/toplev.c
gcc/toplev.h
gcc/tree-cfg.c
gcc/tree.c
gcc/vec.c
gcc/wide-int.cc

index 3e6879849f26679d7617ae3f85bbd6356bf2906c..68a7b78f4b658dd73774fe0ed531402f4c370730 100644 (file)
@@ -1,3 +1,112 @@
+2016-06-06  David Malcolm  <dmalcolm@redhat.com>
+
+       * Makefile.in (OBJS): Add function-tests.o,
+       hash-map-tests.o, hash-set-tests.o, rtl-tests.o,
+       selftest-run-tests.o.
+       (OBJS-libcommon): Add selftest.o.
+       (OBJS-libcommon-target): Add selftest.o.
+       (all.internal): Add "selftest".
+       (all.cross): Likewise.
+       (selftest): New phony target.
+       (s-selftest): New target.
+       (selftest-gdb): New phony target.
+       (COLLECT2_OBJS): Add selftest.o.
+       * bitmap.c: Include "selftest.h".
+       (selftest::test_gc_alloc): New function.
+       (selftest::test_set_range): New function.
+       (selftest::test_clear_bit_in_middle): New function.
+       (selftest::test_copying): New function.
+       (selftest::test_bitmap_single_bit_set_p): New function.
+       (selftest::bitmap_c_tests): New function.
+       * common.opt (fself-test): New.
+       * diagnostic-show-locus.c: Include "selftest.h".
+       (make_range): New function.
+       (test_range_contains_point_for_single_point): New function.
+       (test_range_contains_point_for_single_line): New function.
+       (test_range_contains_point_for_multiple_lines): New function.
+       (assert_eq): New function.
+       (test_get_line_width_without_trailing_whitespace): New function.
+       (selftest::diagnostic_show_locus_c_tests): New function.
+       * et-forest.c: Include "selftest.h".
+       (selftest::test_single_node): New function.
+       (selftest::test_simple_tree): New function.
+       (selftest::test_disconnected_nodes): New function.
+       (selftest::et_forest_c_tests): New function.
+       * fold-const.c: Include "selftest.h".
+       (selftest::assert_binop_folds_to_const): New function.
+       (selftest::assert_binop_folds_to_nonlvalue): New function.
+       (selftest::test_arithmetic_folding): New function.
+       (selftest::fold_const_c_tests): New function.
+       * function-tests.c: New file.
+       * gimple.c: Include "selftest.h".
+       Include "gimple-pretty-print.h".
+       (selftest::verify_gimple_pp): New function.
+       (selftest::test_assign_single): New function.
+       (selftest::test_assign_binop): New function.
+       (selftest::test_nop_stmt): New function.
+       (selftest::test_return_stmt): New function.
+       (selftest::test_return_without_value): New function.
+       (selftest::gimple_c_tests): New function.
+       * hash-map-tests.c: New file.
+       * hash-set-tests.c: New file.
+       * input.c: Include "selftest.h".
+       (selftest::assert_loceq): New function.
+       (selftest::test_accessing_ordinary_linemaps): New function.
+       (selftest::test_unknown_location): New function.
+       (selftest::test_builtins): New function.
+       (selftest::test_reading_source_line): New function.
+       (selftest::input_c_tests): New function.
+       * rtl-tests.c: New file.
+       * selftest-run-tests.c: New file.
+       * selftest.c: New file.
+       * selftest.h: New file.
+       * spellcheck.c: Include "selftest.h".
+       (selftest::levenshtein_distance_unit_test_oneway): New function,
+       adapted from testsuite/gcc.dg/plugin/levenshtein_plugin.c.
+       (selftest::levenshtein_distance_unit_test): Likewise.
+       (selftest::spellcheck_c_tests): Likewise.
+       * toplev.c: Include selftest.h.
+       (toplev::run_self_tests): New.
+       (toplev::main): Handle -fself-test.
+       * toplev.h (toplev::run_self_tests): New.
+       * tree.c: Include "selftest.h".
+       (selftest::test_integer_constants): New function.
+       (selftest::test_identifiers): New function.
+       (selftest::test_labels): New function.
+       (selftest::tree_c_tests): New function.
+       * tree-cfg.c: Include "selftest.h".
+       (selftest::push_fndecl): New function.
+       (selftest::test_linear_chain): New function.
+       (selftest::test_diamond): New function.
+       (selftest::test_fully_connected): New function.
+       (selftest::tree_cfg_c_tests): New function.
+       * vec.c: Include "selftest.h".
+       (selftest::safe_push_range): New function.
+       (selftest::test_quick_push): New function.
+       (selftest::test_safe_push): New function.
+       (selftest::test_truncate): New function.
+       (selftest::test_safe_grow_cleared): New function.
+       (selftest::test_pop): New function.
+       (selftest::test_safe_insert): New function.
+       (selftest::test_ordered_remove): New function.
+       (selftest::test_unordered_remove): New function.
+       (selftest::test_block_remove): New function.
+       (selftest::reverse_cmp): New function.
+       (selftest::test_qsort): New function.
+       (selftest::vec_c_tests): New function.c.
+       * wide-int.cc: Include selftest.h and wide-int-print.h.
+       (selftest::from_int <wide_int>): New function.
+       (selftest::from_int <offset_int>): New function.
+       (selftest::from_int <widest_int>): New function.
+       (selftest::assert_deceq): New function.
+       (selftest::assert_hexeq): New function.
+       (selftest::test_printing <VALUE_TYPE>): New function template.
+       (selftest::test_ops <VALUE_TYPE>): New function template.
+       (selftest::test_comparisons <VALUE_TYPE>): New function template.
+       (selftest::run_all_wide_int_tests <VALUE_TYPE>): New function
+       template.
+       (selftest::wide_int_cc_tests): New function.
+
 2016-06-06  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
 
        PR middle-end/37780
index 2d6f1e8d02fa6607bea9dd7d01d119dfe906348b..fdcc42aa309480660209d2830fd6e2d6d293e1de 100644 (file)
@@ -1264,6 +1264,7 @@ OBJS = \
        fold-const.o \
        fold-const-call.o \
        function.o \
+       function-tests.o \
        fwprop.o \
        gcc-rich-location.o \
        gcse.o \
@@ -1299,6 +1300,8 @@ OBJS = \
        graphite-sese-to-poly.o \
        gtype-desc.o \
        haifa-sched.o \
+       hash-map-tests.o \
+       hash-set-tests.o \
        hsa.o \
        hsa-gen.o \
        hsa-regalloc.o \
@@ -1399,6 +1402,7 @@ OBJS = \
        resource.o \
        rtl-chkp.o \
        rtl-error.o \
+       rtl-tests.o \
        rtl.o \
        rtlhash.o \
        rtlanal.o \
@@ -1411,6 +1415,7 @@ OBJS = \
        sel-sched-ir.o \
        sel-sched-dump.o \
        sel-sched.o \
+       selftest-run-tests.o \
        sese.o \
        shrink-wrap.o \
        simplify-rtx.o \
@@ -1543,13 +1548,14 @@ OBJS = \
 # no target dependencies.
 OBJS-libcommon = diagnostic.o diagnostic-color.o diagnostic-show-locus.o \
        pretty-print.o intl.o \
-       vec.o input.o version.o hash-table.o ggc-none.o memory-block.o
+       vec.o input.o version.o hash-table.o ggc-none.o memory-block.o \
+       selftest.o
 
 # Objects in libcommon-target.a, used by drivers and by the core
 # compiler and containing target-dependent code.
 OBJS-libcommon-target = $(common_out_object_file) prefix.o params.o \
        opts.o opts-common.o options.o vec.o hooks.o common/common-targhooks.o \
-       hash-table.o file-find.o spellcheck.o
+       hash-table.o file-find.o spellcheck.o selftest.o
 
 # This lists all host objects for the front ends.
 ALL_HOST_FRONTEND_OBJS = $(foreach v,$(CONFIG_LANGUAGES),$($(v)_OBJS))
@@ -1816,10 +1822,10 @@ config.status: $(srcdir)/configure $(srcdir)/config.gcc
 quickstrap: all
        cd $(toplevel_builddir) && $(MAKE) all-target-libgcc
 
-all.internal: start.encap rest.encap doc
+all.internal: start.encap rest.encap doc selftest
 # This is what to compile if making a cross-compiler.
 all.cross: native gcc-cross$(exeext) cpp$(exeext) specs \
-       libgcc-support lang.all.cross doc @GENINSRC@ srcextra
+       libgcc-support lang.all.cross doc selftest @GENINSRC@ srcextra
 # This is what must be made before installing GCC and converting libraries.
 start.encap: native xgcc$(exeext) cpp$(exeext) specs \
        libgcc-support lang.start.encap @GENINSRC@ srcextra
@@ -1839,6 +1845,21 @@ endif
 # This does the things that can't be done on the host machine.
 rest.cross: specs
 
+# Run the selftests during the build once we have a driver and a cc1,
+# so that self-test failures are caught as early as possible.
+# Use "s-selftest" to ensure that we only run the selftests if the
+# driver or cc1 change.
+.PHONY: selftest
+selftest: s-selftest
+s-selftest: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs
+       $(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test
+       $(STAMP) $@
+
+# Convenience method for running selftests under gdb:
+.PHONY: selftest-gdb
+selftest-gdb: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs
+       $(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test -wrapper gdb,--args
+
 # Recompile all the language-independent object files.
 # This is used only if the user explicitly asks for it.
 compilations: $(BACKEND)
@@ -1986,7 +2007,7 @@ gcc-nm.c: gcc-ar.c
        cp $^ $@
 
 COLLECT2_OBJS = collect2.o collect2-aix.o tlink.o vec.o ggc-none.o \
-  collect-utils.o file-find.o hash-table.o
+  collect-utils.o file-find.o hash-table.o selftest.o
 COLLECT2_LIBS = @COLLECT2_LIBS@
 collect2$(exeext): $(COLLECT2_OBJS) $(LIBDEPS)
 # Don't try modifying collect2 (aka ld) in place--it might be linking this.
index 010cf752d76bff77843ea0f1c5e94b2c73c72d6c..6206535a8ea9f9a0203f00a4b60c5a1378181065 100644 (file)
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "bitmap.h"
+#include "selftest.h"
 
 /* Memory allocation statistics purpose instance.  */
 mem_alloc_description<bitmap_usage> bitmap_mem_desc;
@@ -2162,5 +2163,117 @@ debug (const bitmap_head *ptr)
     fprintf (stderr, "<nil>\n");
 }
 
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests for bitmaps.  */
+
+/* Freshly-created bitmaps ought to be empty.  */
+
+static void
+test_gc_alloc ()
+{
+  bitmap b = bitmap_gc_alloc ();
+  ASSERT_TRUE (bitmap_empty_p (b));
+}
+
+/* Verify bitmap_set_range.  */
+
+static void
+test_set_range ()
+{
+  bitmap b = bitmap_gc_alloc ();
+  ASSERT_TRUE (bitmap_empty_p (b));
+
+  bitmap_set_range (b, 7, 5);
+  ASSERT_FALSE (bitmap_empty_p (b));
+  ASSERT_EQ (5, bitmap_count_bits (b));
+
+  /* Verify bitmap_bit_p at the boundaries.  */
+  ASSERT_FALSE (bitmap_bit_p (b, 6));
+  ASSERT_TRUE (bitmap_bit_p (b, 7));
+  ASSERT_TRUE (bitmap_bit_p (b, 11));
+  ASSERT_FALSE (bitmap_bit_p (b, 12));
+}
+
+/* Verify splitting a range into two pieces using bitmap_clear_bit.  */
+
+static void
+test_clear_bit_in_middle ()
+{
+  bitmap b = bitmap_gc_alloc ();
+
+  /* Set b to [100..200].  */
+  bitmap_set_range (b, 100, 100);
+  ASSERT_EQ (100, bitmap_count_bits (b));
+
+  /* Clear a bit in the middle.  */
+  bool changed = bitmap_clear_bit (b, 150);
+  ASSERT_TRUE (changed);
+  ASSERT_EQ (99, bitmap_count_bits (b));
+  ASSERT_TRUE (bitmap_bit_p (b, 149));
+  ASSERT_FALSE (bitmap_bit_p (b, 150));
+  ASSERT_TRUE (bitmap_bit_p (b, 151));
+}
+
+/* Verify bitmap_copy.  */
+
+static void
+test_copying ()
+{
+  bitmap src = bitmap_gc_alloc ();
+  bitmap_set_range (src, 40, 10);
+
+  bitmap dst = bitmap_gc_alloc ();
+  ASSERT_FALSE (bitmap_equal_p (src, dst));
+  bitmap_copy (dst, src);
+  ASSERT_TRUE (bitmap_equal_p (src, dst));
+
+  /* Verify that we can make them unequal again...  */
+  bitmap_set_range (src, 70, 5);
+  ASSERT_FALSE (bitmap_equal_p (src, dst));
+
+  /* ...and that changing src after the copy didn't affect
+     the other: */
+  ASSERT_FALSE (bitmap_bit_p (dst, 70));
+}
+
+/* Verify bitmap_single_bit_set_p.  */
+
+static void
+test_bitmap_single_bit_set_p ()
+{
+  bitmap b = bitmap_gc_alloc ();
+
+  ASSERT_FALSE (bitmap_single_bit_set_p (b));
+
+  bitmap_set_range (b, 42, 1);
+  ASSERT_TRUE (bitmap_single_bit_set_p (b));
+  ASSERT_EQ (42, bitmap_first_set_bit (b));
+
+  bitmap_set_range (b, 1066, 1);
+  ASSERT_FALSE (bitmap_single_bit_set_p (b));
+  ASSERT_EQ (42, bitmap_first_set_bit (b));
+
+  bitmap_clear_range (b, 0, 100);
+  ASSERT_TRUE (bitmap_single_bit_set_p (b));
+  ASSERT_EQ (1066, bitmap_first_set_bit (b));
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+bitmap_c_tests ()
+{
+  test_gc_alloc ();
+  test_set_range ();
+  test_clear_bit_in_middle ();
+  test_copying ();
+  test_bitmap_single_bit_set_p ();
+}
+
+} // namespace selftest
+#endif /* CHECKING_P */
 
 #include "gt-bitmap.h"
index 2bb576c51c4add8b8535347b17f775c883e6f7ee..632dd311fba3a94cb22c3bf7ffbb0919a6533bdc 100644 (file)
@@ -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.
index eeccee517160112435192fd722e9fff83eece3f3..7aab658b697c73977e1d7ac5895ea8528da6e6bc 100644 (file)
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "backtrace.h"
 #include "diagnostic.h"
 #include "diagnostic-color.h"
+#include "selftest.h"
 
 #ifdef HAVE_TERMIOS_H
 # include <termios.h>
@@ -442,6 +443,123 @@ layout_range::contains_point (int row, int column) const
   return column <= m_finish.m_column;
 }
 
+#if CHECKING_P
+
+/* A helper function for testing layout_range::contains_point.  */
+
+static layout_range
+make_range (int start_line, int start_col, int end_line, int end_col)
+{
+  const expanded_location start_exploc
+    = {"test.c", start_line, start_col, NULL, false};
+  const expanded_location finish_exploc
+    = {"test.c", end_line, end_col, NULL, false};
+  return layout_range (&start_exploc, &finish_exploc, false,
+                      &start_exploc);
+}
+
+/* Selftests for layout_range::contains_point.  */
+
+/* Selftest for layout_range::contains_point where the layout_range
+   is a range with start==end i.e. a single point.  */
+
+static void
+test_range_contains_point_for_single_point ()
+{
+  layout_range point = make_range (7, 10, 7, 10);
+
+  /* Before the line. */
+  ASSERT_FALSE (point.contains_point (6, 1));
+
+  /* On the line, but before start.  */
+  ASSERT_FALSE (point.contains_point (7, 9));
+
+  /* At the point.  */
+  ASSERT_TRUE (point.contains_point (7, 10));
+
+  /* On the line, after the point.  */
+  ASSERT_FALSE (point.contains_point (7, 11));
+
+  /* After the line.  */
+  ASSERT_FALSE (point.contains_point (8, 1));
+}
+
+/* Selftest for layout_range::contains_point where the layout_range
+   is the single-line range shown as "Example A" above.  */
+
+static void
+test_range_contains_point_for_single_line ()
+{
+  layout_range example_a = make_range (2, 22, 2, 38);
+
+  /* Before the line. */
+  ASSERT_FALSE (example_a.contains_point (1, 1));
+
+  /* On the line, but before start.  */
+  ASSERT_FALSE (example_a.contains_point (2, 21));
+
+  /* On the line, at the start.  */
+  ASSERT_TRUE (example_a.contains_point (2, 22));
+
+  /* On the line, within the range.  */
+  ASSERT_TRUE (example_a.contains_point (2, 23));
+
+  /* On the line, at the end.  */
+  ASSERT_TRUE (example_a.contains_point (2, 38));
+
+  /* On the line, after the end.  */
+  ASSERT_FALSE (example_a.contains_point (2, 39));
+
+  /* After the line.  */
+  ASSERT_FALSE (example_a.contains_point (2, 39));
+}
+
+/* Selftest for layout_range::contains_point where the layout_range
+   is the multi-line range shown as "Example B" above.  */
+
+static void
+test_range_contains_point_for_multiple_lines ()
+{
+  layout_range example_b = make_range (3, 14, 5, 8);
+
+  /* Before first line. */
+  ASSERT_FALSE (example_b.contains_point (1, 1));
+
+  /* On the first line, but before start.  */
+  ASSERT_FALSE (example_b.contains_point (3, 13));
+
+  /* At the start.  */
+  ASSERT_TRUE (example_b.contains_point (3, 14));
+
+  /* On the first line, within the range.  */
+  ASSERT_TRUE (example_b.contains_point (3, 15));
+
+  /* On an interior line.
+     The column number should not matter; try various boundary
+     values.  */
+  ASSERT_TRUE (example_b.contains_point (4, 1));
+  ASSERT_TRUE (example_b.contains_point (4, 7));
+  ASSERT_TRUE (example_b.contains_point (4, 8));
+  ASSERT_TRUE (example_b.contains_point (4, 9));
+  ASSERT_TRUE (example_b.contains_point (4, 13));
+  ASSERT_TRUE (example_b.contains_point (4, 14));
+  ASSERT_TRUE (example_b.contains_point (4, 15));
+
+  /* On the final line, before the end.  */
+  ASSERT_TRUE (example_b.contains_point (5, 7));
+
+  /* On the final line, at the end.  */
+  ASSERT_TRUE (example_b.contains_point (5, 8));
+
+  /* On the final line, after the end.  */
+  ASSERT_FALSE (example_b.contains_point (5, 9));
+
+  /* After the line.  */
+  ASSERT_FALSE (example_b.contains_point (6, 1));
+}
+
+#endif /* #if CHECKING_P */
+
 /* Given a source line LINE of length LINE_WIDTH, determine the width
    without any trailing whitespace.  */
 
@@ -465,6 +583,34 @@ get_line_width_without_trailing_whitespace (const char *line, int line_width)
   return result;
 }
 
+#if CHECKING_P
+
+/* A helper function for testing get_line_width_without_trailing_whitespace.  */
+
+static void
+assert_eq (const char *line, int expected_width)
+{
+  int actual_value
+    = get_line_width_without_trailing_whitespace (line, strlen (line));
+  ASSERT_EQ (actual_value, expected_width);
+}
+
+/* Verify that get_line_width_without_trailing_whitespace is sane for
+   various inputs.  It is not required to handle newlines.  */
+
+static void
+test_get_line_width_without_trailing_whitespace ()
+{
+  assert_eq ("", 0);
+  assert_eq (" ", 0);
+  assert_eq ("\t", 0);
+  assert_eq ("hello world", 11);
+  assert_eq ("hello world     ", 11);
+  assert_eq ("hello world     \t\t  ", 11);
+}
+
+#endif /* #if CHECKING_P */
+
 /* Helper function for layout's ctor, for sanitizing locations relative
    to the primary location within a diagnostic.
 
@@ -1171,3 +1317,23 @@ diagnostic_show_locus (diagnostic_context * context,
 
   pp_set_prefix (context->printer, saved_prefix);
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Run all of the selftests within this file.  */
+
+void
+diagnostic_show_locus_c_tests ()
+{
+  test_range_contains_point_for_single_point ();
+  test_range_contains_point_for_single_line ();
+  test_range_contains_point_for_multiple_lines ();
+
+  test_get_line_width_without_trailing_whitespace ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
index cd36752a27735d15efaeb7edb899a1bafe8a1a72..766a1a3f35b239bfa373da2d736b9732d0223e45 100644 (file)
@@ -27,6 +27,7 @@ License along with libiberty; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "alloc-pool.h"
 #include "et-forest.h"
+#include "selftest.h"
 
 /* We do not enable this with CHECKING_P, since it is awfully slow.  */
 #undef DEBUG_ET
@@ -764,3 +765,120 @@ et_root (struct et_node *node)
 
   return r->of;
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests for et-forest.c.  */
+
+/* Perform sanity checks for a tree consisting of a single node.  */
+
+static void
+test_single_node ()
+{
+  void *test_data = (void *)0xcafebabe;
+
+  et_node *n = et_new_tree (test_data);
+  ASSERT_EQ (n->data, test_data);
+  ASSERT_EQ (n, et_root (n));
+  et_free_tree (n);
+}
+
+/* Test of this tree:
+       a
+      / \
+     /   \
+    b     c
+   / \    |
+  d   e   f.  */
+
+static void
+test_simple_tree ()
+{
+  et_node *a = et_new_tree (NULL);
+  et_node *b = et_new_tree (NULL);
+  et_node *c = et_new_tree (NULL);
+  et_node *d = et_new_tree (NULL);
+  et_node *e = et_new_tree (NULL);
+  et_node *f = et_new_tree (NULL);
+
+  et_set_father (b, a);
+  et_set_father (c, a);
+  et_set_father (d, b);
+  et_set_father (e, b);
+  et_set_father (f, c);
+
+  ASSERT_TRUE (et_below (a, a));
+  ASSERT_TRUE (et_below (b, a));
+  ASSERT_TRUE (et_below (c, a));
+  ASSERT_TRUE (et_below (d, a));
+  ASSERT_TRUE (et_below (e, a));
+  ASSERT_TRUE (et_below (f, a));
+
+  ASSERT_FALSE (et_below (a, b));
+  ASSERT_TRUE (et_below (b, b));
+  ASSERT_FALSE (et_below (c, b));
+  ASSERT_TRUE (et_below (d, b));
+  ASSERT_TRUE (et_below (e, b));
+  ASSERT_FALSE (et_below (f, b));
+
+  ASSERT_FALSE (et_below (a, c));
+  ASSERT_FALSE (et_below (b, c));
+  ASSERT_TRUE (et_below (c, c));
+  ASSERT_FALSE (et_below (d, c));
+  ASSERT_FALSE (et_below (e, c));
+  ASSERT_TRUE (et_below (f, c));
+
+  ASSERT_FALSE (et_below (a, d));
+  ASSERT_FALSE (et_below (b, d));
+  ASSERT_FALSE (et_below (c, d));
+  ASSERT_TRUE (et_below (d, d));
+  ASSERT_FALSE (et_below (e, d));
+  ASSERT_FALSE (et_below (f, d));
+
+  ASSERT_FALSE (et_below (a, e));
+  ASSERT_FALSE (et_below (b, e));
+  ASSERT_FALSE (et_below (c, e));
+  ASSERT_FALSE (et_below (d, e));
+  ASSERT_TRUE (et_below (e, e));
+  ASSERT_FALSE (et_below (f, e));
+
+  ASSERT_FALSE (et_below (a, f));
+  ASSERT_FALSE (et_below (b, f));
+  ASSERT_FALSE (et_below (c, f));
+  ASSERT_FALSE (et_below (d, f));
+  ASSERT_FALSE (et_below (e, f));
+  ASSERT_TRUE (et_below (f, f));
+
+  et_free_tree_force (a);
+}
+
+/* Verify that two disconnected nodes are unrelated.  */
+
+static void
+test_disconnected_nodes ()
+{
+  et_node *a = et_new_tree (NULL);
+  et_node *b = et_new_tree (NULL);
+
+  ASSERT_FALSE (et_below (a, b));
+  ASSERT_FALSE (et_below (b, a));
+
+  et_free_tree (a);
+  et_free_tree (b);
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+et_forest_c_tests ()
+{
+  test_single_node ();
+  test_simple_tree ();
+  test_disconnected_nodes ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
index 5058746c4eb84e2fb3b9c18ccf489a2467439ee9..0efa9d5b0b1dd338a324c5a75ddc5b7a8545a013 100644 (file)
@@ -76,6 +76,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "case-cfn-macros.h"
 #include "stringpool.h"
 #include "tree-ssanames.h"
+#include "selftest.h"
 
 #ifndef LOAD_EXTEND_OP
 #define LOAD_EXTEND_OP(M) UNKNOWN
@@ -14496,3 +14497,82 @@ c_getstr (tree src)
 
   return TREE_STRING_POINTER (src) + tree_to_uhwi (offset_node);
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Helper functions for writing tests of folding trees.  */
+
+/* Verify that the binary op (LHS CODE RHS) folds to CONSTANT.  */
+
+static void
+assert_binop_folds_to_const (tree lhs, enum tree_code code, tree rhs,
+                            tree constant)
+{
+  ASSERT_EQ (constant, fold_build2 (code, TREE_TYPE (lhs), lhs, rhs));
+}
+
+/* Verify that the binary op (LHS CODE RHS) folds to an NON_LVALUE_EXPR
+   wrapping WRAPPED_EXPR.  */
+
+static void
+assert_binop_folds_to_nonlvalue (tree lhs, enum tree_code code, tree rhs,
+                                tree wrapped_expr)
+{
+  tree result = fold_build2 (code, TREE_TYPE (lhs), lhs, rhs);
+  ASSERT_NE (wrapped_expr, result);
+  ASSERT_EQ (NON_LVALUE_EXPR, TREE_CODE (result));
+  ASSERT_EQ (wrapped_expr, TREE_OPERAND (result, 0));
+}
+
+/* Verify that various arithmetic binary operations are folded
+   correctly.  */
+
+static void
+test_arithmetic_folding ()
+{
+  tree type = integer_type_node;
+  tree x = create_tmp_var_raw (type, "x");
+  tree zero = build_zero_cst (type);
+  tree one = build_int_cst (type, 1);
+
+  /* Addition.  */
+  /* 1 <-- (0 + 1) */
+  assert_binop_folds_to_const (zero, PLUS_EXPR, one,
+                              one);
+  assert_binop_folds_to_const (one, PLUS_EXPR, zero,
+                              one);
+
+  /* (nonlvalue)x <-- (x + 0) */
+  assert_binop_folds_to_nonlvalue (x, PLUS_EXPR, zero,
+                                  x);
+
+  /* Subtraction.  */
+  /* 0 <-- (x - x) */
+  assert_binop_folds_to_const (x, MINUS_EXPR, x,
+                              zero);
+  assert_binop_folds_to_nonlvalue (x, MINUS_EXPR, zero,
+                                  x);
+
+  /* Multiplication.  */
+  /* 0 <-- (x * 0) */
+  assert_binop_folds_to_const (x, MULT_EXPR, zero,
+                              zero);
+
+  /* (nonlvalue)x <-- (x * 1) */
+  assert_binop_folds_to_nonlvalue (x, MULT_EXPR, one,
+                                  x);
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+fold_const_c_tests ()
+{
+  test_arithmetic_folding ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
diff --git a/gcc/function-tests.c b/gcc/function-tests.c
new file mode 100644 (file)
index 0000000..c8188e7
--- /dev/null
@@ -0,0 +1,658 @@
+/* Unit tests for function-handling.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "hard-reg-set.h"
+#include "input.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "gimple-expr.h"
+#include "toplev.h"
+#include "print-tree.h"
+#include "tree-iterator.h"
+#include "gimplify.h"
+#include "tree-cfg.h"
+#include "basic-block.h"
+#include "double-int.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "stmt.h"
+#include "hash-table.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "context.h"
+#include "hash-map.h"
+#include "plugin-api.h"
+#include "ipa-ref.h"
+#include "cgraph.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Helper function for selftests of function-creation.  */
+
+static tree
+make_fndecl (tree return_type,
+            const char *name,
+            vec <tree> &param_types,
+            bool is_variadic = false)
+{
+  tree fn_type;
+  if (is_variadic)
+    fn_type = build_varargs_function_type_array (return_type,
+                                                param_types.length (),
+                                                param_types.address ());
+  else
+    fn_type = build_function_type_array (return_type,
+                                        param_types.length (),
+                                        param_types.address ());
+  /* FIXME: this uses input_location: */
+  tree fndecl = build_fn_decl (name, fn_type);
+
+  return fndecl;
+}
+
+/* Verify creating a function declaration equivalent to the following
+     int test_fndecl_int_void (void);
+   C declaration.  */
+
+static void
+test_fndecl_int_void ()
+{
+  auto_vec <tree> param_types;
+  const char *name = "test_fndecl_int_void";
+  tree fndecl = make_fndecl (integer_type_node,
+                            name,
+                            param_types);
+  ASSERT_TRUE (fndecl != NULL);
+
+  /* Verify name of decl.  */
+  tree declname = DECL_NAME (fndecl);
+  ASSERT_TRUE (declname != NULL);
+  ASSERT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
+  /* We expect it to use a *copy* of the string we passed in.  */
+  const char *identifier_ptr = IDENTIFIER_POINTER (declname);
+  ASSERT_NE (name, identifier_ptr);
+  ASSERT_EQ (0, strcmp ("test_fndecl_int_void", identifier_ptr));
+
+  /* Verify type of fndecl.  */
+  ASSERT_EQ (FUNCTION_DECL, TREE_CODE (fndecl));
+  tree fntype = TREE_TYPE (fndecl);
+  ASSERT_EQ (FUNCTION_TYPE, TREE_CODE (fntype));
+
+  /* Verify return type.  */
+  ASSERT_EQ (integer_type_node, TREE_TYPE (fntype));
+
+  /* Verify "void" args.  */
+  tree argtypes = TYPE_ARG_TYPES (fntype);
+  ASSERT_EQ (TREE_LIST, TREE_CODE (argtypes));
+  ASSERT_EQ (void_type_node, TREE_VALUE (argtypes));
+  ASSERT_EQ (NULL, TREE_CHAIN (argtypes));
+}
+
+/* Verify creating a function declaration equivalent to the following
+     float test_fndecl_float_intchar (int, char);
+   C declaration.  */
+
+static void
+test_fndecl_float_intchar ()
+{
+  auto_vec <tree> param_types;
+  param_types.safe_push (integer_type_node);
+  param_types.safe_push (char_type_node);
+  const char *name = "test_fndecl_float_intchar";
+  tree fndecl = make_fndecl (float_type_node,
+                            name,
+                            param_types);
+  ASSERT_TRUE (fndecl != NULL);
+
+  /* Verify name of decl.  */
+  tree declname = DECL_NAME (fndecl);
+  ASSERT_TRUE (declname != NULL);
+  ASSERT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
+  /* We expect it to use a *copy* of the string we passed in.  */
+  const char *identifier_ptr = IDENTIFIER_POINTER (declname);
+  ASSERT_NE (name, identifier_ptr);
+  ASSERT_EQ (0, strcmp (name, identifier_ptr));
+
+  /* Verify type of fndecl.  */
+  ASSERT_EQ (FUNCTION_DECL, TREE_CODE (fndecl));
+  tree fntype = TREE_TYPE (fndecl);
+  ASSERT_EQ (FUNCTION_TYPE, TREE_CODE (fntype));
+
+  /* Verify return type.  */
+  ASSERT_EQ (float_type_node, TREE_TYPE (fntype));
+
+  /* Verify "(int, char)" args.  */
+  tree arg0 = TYPE_ARG_TYPES (fntype);
+  ASSERT_EQ (TREE_LIST, TREE_CODE (arg0));
+  ASSERT_EQ (integer_type_node, TREE_VALUE (arg0));
+  tree arg1 = TREE_CHAIN (arg0);
+  ASSERT_TRUE (arg1 != NULL);
+  ASSERT_EQ (TREE_LIST, TREE_CODE (arg1));
+  ASSERT_EQ (char_type_node, TREE_VALUE (arg1));
+  tree argterm = TREE_CHAIN (arg1);
+  ASSERT_TRUE (argterm != NULL);
+  ASSERT_EQ (TREE_LIST, TREE_CODE (argterm));
+  ASSERT_EQ (void_type_node, TREE_VALUE (argterm));
+  ASSERT_EQ (NULL, TREE_CHAIN (argterm));
+}
+
+/* The test cases using these helper functions take a trivial function:
+
+     int test_fn (void) { return 42; }
+
+   and test various conversions done to it:
+
+   - gimplification
+   - construction of the CFG
+   - conversion to SSA form
+   - expansion to RTL form
+
+   In avoid having one overlong test case, this is broken
+   up into separate test cases for each stage, with helper functions
+   to minimize code duplication.
+
+   Another approach would be to attempt to directly construct a function
+   in the appropriate representation at each stage, though presumably
+   that would exhibit different kinds of failure compared to this
+   approach.  */
+
+/* Construct this function:
+   int test_fn (void) { return 42; }
+   in generic tree form.  Return the fndecl.  */
+
+static tree
+build_trivial_generic_function ()
+{
+  auto_vec <tree> param_types;
+  tree fndecl = make_fndecl (integer_type_node,
+                            "test_fn",
+                            param_types);
+  ASSERT_TRUE (fndecl != NULL);
+
+  /* Populate the function.  */
+  tree retval = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+                           NULL_TREE, integer_type_node);
+  DECL_ARTIFICIAL (retval) = 1;
+  DECL_IGNORED_P (retval) = 1;
+  DECL_RESULT (fndecl) = retval;
+
+  /* Create a BIND_EXPR, and within it, a statement list.  */
+  tree stmt_list = alloc_stmt_list ();
+  tree_stmt_iterator stmt_iter = tsi_start (stmt_list);
+  tree block = make_node (BLOCK);
+  tree bind_expr
+    = build3 (BIND_EXPR, void_type_node, NULL, stmt_list, block);
+
+  tree modify_retval = build2 (MODIFY_EXPR,
+                              integer_type_node,
+                              retval,
+                              build_int_cst (integer_type_node, 42));
+  tree return_stmt = build1 (RETURN_EXPR,
+                            integer_type_node,
+                            modify_retval);
+  tsi_link_after (&stmt_iter, return_stmt, TSI_CONTINUE_LINKING);
+
+  DECL_INITIAL (fndecl) = block;
+
+  /* how to add to function? the following appears to be how to
+     set the body of a fndecl: */
+  DECL_SAVED_TREE(fndecl) = bind_expr;
+
+  /* Ensure that locals appear in the debuginfo.  */
+  BLOCK_VARS (block) = BIND_EXPR_VARS (bind_expr);
+
+  return fndecl;
+}
+
+/* Construct this function:
+     int test_fn (void) { return 42; }
+   in "high gimple" form.  Return the fndecl.  */
+
+static tree
+build_trivial_high_gimple_function ()
+{
+  /* Construct a trivial function, and gimplify it: */
+  tree fndecl = build_trivial_generic_function ();
+  gimplify_function_tree (fndecl);
+  return fndecl;
+}
+
+/* Build a CFG for a function in gimple form.  */
+
+static void
+build_cfg (tree fndecl)
+{
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  ASSERT_EQ (fndecl, fun->decl);
+
+  /* We first have to lower control flow; for our trivial test function
+     this gives us:
+        test_fn ()
+        {
+          D.56 = 42;
+          goto <D.57>;
+          <D.57>:
+          return D.56;
+        }
+  */
+  gimple_opt_pass *lower_cf_pass = make_pass_lower_cf (g);
+  push_cfun (fun);
+  lower_cf_pass->execute (fun);
+  pop_cfun ();
+
+  /* We can now convert to CFG form; for our trivial test function this
+     gives us:
+        test_fn ()
+        {
+          <bb 2>:
+          D.56 = 42;
+          return D.56;
+        }
+  */
+  gimple_opt_pass *build_cfg_pass = make_pass_build_cfg (g);
+  push_cfun (fun);
+  build_cfg_pass->execute (fun);
+  pop_cfun ();
+}
+
+/* Convert a gimple+CFG function to SSA form.  */
+
+static void
+convert_to_ssa (tree fndecl)
+{
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  ASSERT_EQ (fndecl, fun->decl);
+
+  gimple_opt_pass *build_ssa_pass = make_pass_build_ssa (g);
+  push_cfun (fun);
+  build_ssa_pass->execute (fun);
+  pop_cfun ();
+}
+
+/* Assuming we have a simple 3-block CFG like this:
+     [ENTRY] -> [block2] -> [EXIT]
+   get the "real" basic block (block 2).  */
+
+static basic_block
+get_real_block (function *fun)
+{
+  ASSERT_TRUE (fun->cfg != NULL);
+  ASSERT_EQ (3, n_basic_blocks_for_fn (fun));
+  basic_block bb2 = (*fun->cfg->x_basic_block_info)[2];
+  ASSERT_TRUE (bb2 != NULL);
+  return bb2;
+}
+
+/* Verify that we have a simple 3-block CFG: the two "fake" ones, and
+   a "real" one:
+     [ENTRY] -> [block2] -> [EXIT].  */
+
+static void
+verify_three_block_cfg (function *fun)
+{
+  ASSERT_TRUE (fun->cfg != NULL);
+  ASSERT_EQ (3, n_basic_blocks_for_fn (fun));
+  ASSERT_EQ (2, n_edges_for_fn (fun));
+
+  /* The "fake" basic blocks.  */
+  basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (entry != NULL);
+  ASSERT_EQ (ENTRY_BLOCK, entry->index);
+
+  basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (exit != NULL);
+  ASSERT_EQ (EXIT_BLOCK, exit->index);
+
+  /* The "real" basic block.  */
+  basic_block bb2 = get_real_block (fun);
+  ASSERT_TRUE (bb2 != NULL);
+  ASSERT_EQ (2, bb2->index);
+
+  /* Verify connectivity.  */
+  ASSERT_EQ (NULL, entry->preds);
+  ASSERT_EQ (1, entry->succs->length ());
+
+  edge from_entry_to_bb2 = (*entry->succs)[0];
+  ASSERT_EQ (entry, from_entry_to_bb2->src);
+  ASSERT_EQ (bb2, from_entry_to_bb2->dest);
+
+  ASSERT_EQ (1, bb2->preds->length ());
+  ASSERT_EQ (from_entry_to_bb2, (*bb2->preds)[0]);
+  ASSERT_EQ (1, bb2->succs->length ());
+
+  edge from_bb2_to_exit = (*bb2->succs)[0];
+  ASSERT_EQ (bb2, from_bb2_to_exit->src);
+  ASSERT_EQ (exit, from_bb2_to_exit->dest);
+
+  ASSERT_EQ (1, exit->preds->length ());
+  ASSERT_EQ (from_bb2_to_exit, (*exit->preds)[0]);
+  ASSERT_EQ (NULL, exit->succs);
+}
+
+/* As above, but additionally verify the gimple statements are sane.  */
+
+static void
+verify_three_block_gimple_cfg (function *fun)
+{
+  verify_three_block_cfg (fun);
+
+  /* The "fake" basic blocks should be flagged as gimple, but with have no
+     statements.  */
+  basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (entry != NULL);
+  ASSERT_EQ (0, entry->flags & BB_RTL);
+  ASSERT_EQ (NULL, bb_seq (entry));
+
+  basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (exit != NULL);
+  ASSERT_EQ (0, entry->flags & BB_RTL);
+  ASSERT_EQ (NULL, bb_seq (exit));
+
+  /* The "real" basic block should be flagged as gimple, and have one
+     or more statements.  */
+  basic_block bb2 = get_real_block (fun);
+  ASSERT_TRUE (bb2 != NULL);
+  ASSERT_EQ (0, entry->flags & BB_RTL);
+  ASSERT_TRUE (bb_seq (bb2) != NULL);
+}
+
+/* As above, but additionally verify the RTL insns are sane.  */
+
+static void
+verify_three_block_rtl_cfg (function *fun)
+{
+  verify_three_block_cfg (fun);
+
+  /* The "fake" basic blocks should be flagged as RTL, but with no
+     insns.  */
+  basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (entry != NULL);
+  ASSERT_EQ (BB_RTL, entry->flags & BB_RTL);
+  ASSERT_EQ (NULL, BB_HEAD (entry));
+
+  basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
+  ASSERT_TRUE (exit != NULL);
+  ASSERT_EQ (BB_RTL, entry->flags & BB_RTL);
+  ASSERT_EQ (NULL, BB_HEAD (exit));
+
+  /* The "real" basic block should be flagged as RTL, and have one
+     or more insns.  */
+  basic_block bb2 = get_real_block (fun);
+  ASSERT_TRUE (bb2 != NULL);
+  ASSERT_EQ (BB_RTL, entry->flags & BB_RTL);
+  ASSERT_TRUE (BB_HEAD (bb2) != NULL);
+}
+
+/* Test converting our trivial function:
+     int test_fn (void) { return 42; }
+   to gimple form.  */
+
+static void
+test_gimplification ()
+{
+  tree fndecl = build_trivial_generic_function ();
+
+  /* Convert to gimple: */
+  gimplify_function_tree (fndecl);
+
+  /* Verify that we got gimple out of it.  */
+
+  /* The function is now in GIMPLE form but the CFG has not been
+     built yet.  */
+
+  /* We should have a struct function for the decl.  */
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  ASSERT_EQ (fndecl, fun->decl);
+
+  /* We expect a GIMPLE_BIND, with two gimple statements within it:
+       tmp = 42;
+       return tmp;  */
+
+  gimple_seq seq_fn_body = gimple_body (fndecl);
+  ASSERT_TRUE (seq_fn_body != NULL);
+  gimple *bind_stmt = gimple_seq_first_stmt (seq_fn_body);
+  ASSERT_EQ (GIMPLE_BIND, gimple_code (bind_stmt));
+  ASSERT_EQ (NULL, bind_stmt->next);
+
+  gimple_seq seq_bind_body = gimple_bind_body (as_a <gbind *> (bind_stmt));
+
+  /* Verify that we have the 2 statements we expect.  */
+  ASSERT_TRUE (seq_bind_body != NULL);
+  gimple *stmt1 = gimple_seq_first_stmt (seq_bind_body);
+  ASSERT_TRUE (stmt1 != NULL);
+  ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt1));
+  gimple *stmt2 = stmt1->next;
+  ASSERT_TRUE (stmt2 != NULL);
+  ASSERT_EQ (stmt1, stmt2->prev);
+  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt2));
+}
+
+/* Test of building a CFG for a function in high gimple form.  */
+
+static void
+test_building_cfg ()
+{
+  /* Construct a trivial function, and gimplify it: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+
+  /* Build a CFG.  */
+  build_cfg (fndecl);
+
+  /* The CFG-building code constructs a 4-block cfg (with
+     ENTRY and EXIT):
+       test_fn ()
+       {
+         <bb 2>:
+        D.65 = 42;
+
+        <bb 3>:
+        return D.65;
+       }
+     and then ought to merge blocks 2 and 3 in cleanup_tree_cfg.
+
+     Hence we should end up with a simple 3-block cfg, the two "fake" ones,
+     and a "real" one:
+       [ENTRY] -> [block2] -> [EXIT]
+     with code like this:
+        test_fn ()
+        {
+          <bb 2>:
+          D.56 = 42;
+          return D.56;
+        }
+  */
+  verify_three_block_gimple_cfg (fun);
+
+  /* Verify the statements within the "real" block.  */
+  basic_block bb2 = get_real_block (fun);
+  gimple *stmt_a = gimple_seq_first_stmt (bb_seq (bb2));
+  ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a));
+  gimple *stmt_b = stmt_a->next;
+  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt_b));
+  ASSERT_EQ (NULL, stmt_b->next);
+}
+
+/* Test of conversion of gimple to SSA form.  */
+
+static void
+test_conversion_to_ssa ()
+{
+  /* As above, construct a trivial function, gimplify it, and build a CFG: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  build_cfg (fndecl);
+
+  convert_to_ssa (fndecl);
+
+  verify_three_block_gimple_cfg (fun);
+
+  /* For out trivial test function we should now have something like
+     this:
+       test_fn ()
+       {
+        <bb 2>:
+        _1 = 42;
+        return _1;
+       }
+  */
+  basic_block bb2 = get_real_block (fun);
+  gimple *stmt_a = gimple_seq_first_stmt (bb_seq (bb2));
+  ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a));
+
+  gimple *stmt_b = stmt_a->next;
+  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt_b));
+  ASSERT_EQ (NULL, stmt_b->next);
+
+  greturn *return_stmt = as_a <greturn *> (stmt_b);
+  ASSERT_EQ (SSA_NAME, TREE_CODE (gimple_return_retval (return_stmt)));
+}
+
+/* Test of expansion from gimple-ssa to RTL.  */
+
+static void
+test_expansion_to_rtl ()
+{
+  /* As above, construct a trivial function, gimplify it, build a CFG,
+     and convert to SSA: */
+  tree fndecl = build_trivial_high_gimple_function ();
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  build_cfg (fndecl);
+  convert_to_ssa (fndecl);
+
+  /* We need a cgraph_node for it.  */
+  cgraph_node::get_create (fndecl);
+  /* Normally, cgraph_node::expand () would call
+     init_function_start (and a bunch of other stuff),
+     and invoke the expand pass, but it also runs
+     all of the other passes.  So just do the minimum
+     needed to get from gimple-SSA to RTL.  */
+  rtl_opt_pass *expand_pass = make_pass_expand (g);
+  push_cfun (fun);
+  init_function_start (fndecl);
+  expand_pass->execute (fun);
+  pop_cfun ();
+
+  /* On x86_64, I get this:
+       (note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+       (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
+       (insn 5 2 6 2 (set (reg:SI 87 [ D.59 ])
+                         (const_int 42 [0x2a])) -1 (nil))
+       (insn 6 5 10 2 (set (reg:SI 88 [ <retval> ])
+                          (reg:SI 87 [ D.59 ])) -1 (nil))
+       (insn 10 6 11 2 (set (reg/i:SI 0 ax)
+                           (reg:SI 88 [ <retval> ])) -1 (nil))
+       (insn 11 10 0 2 (use (reg/i:SI 0 ax)) -1 (nil))
+
+     On cr16-elf I get this:
+       (note 4 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+       (insn 2 4 3 2 (set (reg:SI 24)
+           (reg/f:SI 16 virtual-incoming-args)) -1
+         (nil))
+       (note 3 2 6 2 NOTE_INSN_FUNCTION_BEG)
+       (insn 6 3 7 2 (set (reg:HI 22 [ _1 ])
+           (const_int 42 [0x2a])) -1
+        (nil))
+       (insn 7 6 11 2 (set (reg:HI 23 [ <retval> ])
+          (reg:HI 22 [ _1 ])) -1
+        (nil))
+       (insn 11 7 12 2 (set (reg/i:HI 0 r0)
+          (reg:HI 23 [ <retval> ])) -1
+        (nil))
+       (insn 12 11 0 2 (use (reg/i:HI 0 r0)) -1
+        (nil)).  */
+  verify_three_block_rtl_cfg (fun);
+
+  /* Verify as much of the RTL as we can whilst avoiding
+     target-specific behavior.  */
+  basic_block bb2 = get_real_block (fun);
+
+  /* Expect a NOTE_INSN_BASIC_BLOCK... */
+  rtx_insn *insn = BB_HEAD (bb2);
+  ASSERT_TRUE (insn != NULL);
+  ASSERT_EQ (NOTE, insn->code);
+  ASSERT_EQ (NOTE_INSN_BASIC_BLOCK, NOTE_KIND (insn));
+  ASSERT_EQ (bb2, NOTE_BASIC_BLOCK (insn));
+
+  /* ...etc; any further checks are likely to over-specify things
+     and run us into target dependencies.  */
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+function_tests_c_tests ()
+{
+  test_fndecl_int_void ();
+  test_fndecl_float_intchar ();
+  test_gimplification ();
+  test_building_cfg ();
+  test_conversion_to_ssa ();
+  test_expansion_to_rtl ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
index 75a1ed8ee0ba71c754647f0a346e176a5d029f52..178c1d3a517d586358e374b1348468091cb707e5 100644 (file)
@@ -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
@@ -3022,3 +3024,138 @@ maybe_remove_unused_call_args (struct function *fn, gimple *stmt)
       update_stmt_fn (fn, stmt);
     }
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests for core gimple structures.  */
+
+/* Verify that STMT is pretty-printed as EXPECTED.
+   Helper function for selftests.  */
+
+static void
+verify_gimple_pp (const char *expected, gimple *stmt)
+{
+  pretty_printer pp;
+  pp_gimple_stmt_1 (&pp, stmt, 0 /* spc */, 0 /* flags */);
+  ASSERT_STREQ (expected, pp_formatted_text (&pp));
+}
+
+/* Build a GIMPLE_ASSIGN equivalent to
+     tmp = 5;
+   and verify various properties of it.  */
+
+static void
+test_assign_single ()
+{
+  tree type = integer_type_node;
+  tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+                        get_identifier ("tmp"),
+                        type);
+  tree rhs = build_int_cst (type, 5);
+  gassign *stmt = gimple_build_assign (lhs, rhs);
+  verify_gimple_pp ("tmp = 5;", stmt);
+
+  ASSERT_TRUE (is_gimple_assign (stmt));
+  ASSERT_EQ (lhs, gimple_assign_lhs (stmt));
+  ASSERT_EQ (lhs, gimple_get_lhs (stmt));
+  ASSERT_EQ (rhs, gimple_assign_rhs1 (stmt));
+  ASSERT_EQ (NULL, gimple_assign_rhs2 (stmt));
+  ASSERT_EQ (NULL, gimple_assign_rhs3 (stmt));
+  ASSERT_TRUE (gimple_assign_single_p (stmt));
+  ASSERT_EQ (INTEGER_CST, gimple_assign_rhs_code (stmt));
+}
+
+/* Build a GIMPLE_ASSIGN equivalent to
+     tmp = a * b;
+   and verify various properties of it.  */
+
+static void
+test_assign_binop ()
+{
+  tree type = integer_type_node;
+  tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+                        get_identifier ("tmp"),
+                        type);
+  tree a = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+                      get_identifier ("a"),
+                      type);
+  tree b = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+                      get_identifier ("b"),
+                      type);
+  gassign *stmt = gimple_build_assign (lhs, MULT_EXPR, a, b);
+  verify_gimple_pp ("tmp = a * b;", stmt);
+
+  ASSERT_TRUE (is_gimple_assign (stmt));
+  ASSERT_EQ (lhs, gimple_assign_lhs (stmt));
+  ASSERT_EQ (lhs, gimple_get_lhs (stmt));
+  ASSERT_EQ (a, gimple_assign_rhs1 (stmt));
+  ASSERT_EQ (b, gimple_assign_rhs2 (stmt));
+  ASSERT_EQ (NULL, gimple_assign_rhs3 (stmt));
+  ASSERT_FALSE (gimple_assign_single_p (stmt));
+  ASSERT_EQ (MULT_EXPR, gimple_assign_rhs_code (stmt));
+}
+
+/* Build a GIMPLE_NOP and verify various properties of it.  */
+
+static void
+test_nop_stmt ()
+{
+  gimple *stmt = gimple_build_nop ();
+  verify_gimple_pp ("GIMPLE_NOP", stmt);
+  ASSERT_EQ (GIMPLE_NOP, gimple_code (stmt));
+  ASSERT_EQ (NULL, gimple_get_lhs (stmt));
+  ASSERT_FALSE (gimple_assign_single_p (stmt));
+}
+
+/* Build a GIMPLE_RETURN equivalent to
+     return 7;
+   and verify various properties of it.  */
+
+static void
+test_return_stmt ()
+{
+  tree type = integer_type_node;
+  tree val = build_int_cst (type, 7);
+  greturn *stmt = gimple_build_return (val);
+  verify_gimple_pp ("return 7;", stmt);
+
+  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt));
+  ASSERT_EQ (NULL, gimple_get_lhs (stmt));
+  ASSERT_EQ (val, gimple_return_retval (stmt));
+  ASSERT_FALSE (gimple_assign_single_p (stmt));
+}
+
+/* Build a GIMPLE_RETURN equivalent to
+     return;
+   and verify various properties of it.  */
+
+static void
+test_return_without_value ()
+{
+  greturn *stmt = gimple_build_return (NULL);
+  verify_gimple_pp ("return;", stmt);
+
+  ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt));
+  ASSERT_EQ (NULL, gimple_get_lhs (stmt));
+  ASSERT_EQ (NULL, gimple_return_retval (stmt));
+  ASSERT_FALSE (gimple_assign_single_p (stmt));
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+gimple_c_tests ()
+{
+  test_assign_single ();
+  test_assign_binop ();
+  test_nop_stmt ();
+  test_return_stmt ();
+  test_return_without_value ();
+}
+
+} // namespace selftest
+
+
+#endif /* CHECKING_P */
diff --git a/gcc/hash-map-tests.c b/gcc/hash-map-tests.c
new file mode 100644 (file)
index 0000000..fd1bb95
--- /dev/null
@@ -0,0 +1,93 @@
+/* Unit tests for hash-map.h.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Construct a hash_map <const char *, int> and verify that
+   various operations work correctly.  */
+
+static void
+test_map_of_strings_to_int ()
+{
+  hash_map <const char *, int> m;
+
+  const char *ostrich = "ostrich";
+  const char *elephant = "elephant";
+  const char *ant = "ant";
+  const char *spider = "spider";
+  const char *millipede = "Illacme plenipes";
+  const char *eric = "half a bee";
+
+  /* A fresh hash_map should be empty.  */
+  ASSERT_EQ (0, m.elements ());
+  ASSERT_EQ (NULL, m.get (ostrich));
+
+  /* Populate the hash_map.  */
+  ASSERT_EQ (false, m.put (ostrich, 2));
+  ASSERT_EQ (false, m.put (elephant, 4));
+  ASSERT_EQ (false, m.put (ant, 6));
+  ASSERT_EQ (false, m.put (spider, 8));
+  ASSERT_EQ (false, m.put (millipede, 750));
+  ASSERT_EQ (false, m.put (eric, 3));
+
+  /* Verify that we can recover the stored values.  */
+  ASSERT_EQ (6, m.elements ());
+  ASSERT_EQ (2, *m.get (ostrich));
+  ASSERT_EQ (4, *m.get (elephant));
+  ASSERT_EQ (6, *m.get (ant));
+  ASSERT_EQ (8, *m.get (spider));
+  ASSERT_EQ (750, *m.get (millipede));
+  ASSERT_EQ (3, *m.get (eric));
+
+  /* Verify removing an item.  */
+  m.remove (eric);
+  ASSERT_EQ (5, m.elements ());
+  ASSERT_EQ (NULL, m.get (eric));
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+hash_map_tests_c_tests ()
+{
+  test_map_of_strings_to_int ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
diff --git a/gcc/hash-set-tests.c b/gcc/hash-set-tests.c
new file mode 100644 (file)
index 0000000..db408f2
--- /dev/null
@@ -0,0 +1,69 @@
+/* Unit tests for hash-set.h.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Construct a hash_set <const char *> and verify that various operations
+   work correctly.  */
+
+static void
+test_set_of_strings ()
+{
+  hash_set <const char *> s;
+  ASSERT_EQ (0, s.elements ());
+
+  const char *red = "red";
+  const char *green = "green";
+  const char *blue = "blue";
+
+  ASSERT_EQ (false, s.contains (red));
+
+  /* Populate the hash_set.  */
+  ASSERT_EQ (false, s.add (red));
+  ASSERT_EQ (false, s.add (green));
+  ASSERT_EQ (false, s.add (blue));
+
+  /* Verify that the values are now within the set.  */
+  ASSERT_EQ (true, s.contains (red));
+  ASSERT_EQ (true, s.contains (green));
+  ASSERT_EQ (true, s.contains (blue));
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+hash_set_tests_c_tests ()
+{
+  test_set_of_strings ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
index 61b1e4477fc3cd0ed1e80b584983d240ebcd905d..0b340a8ed9d150af160fe219ceb3db6917a50e70 100644 (file)
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "intl.h"
 #include "diagnostic-core.h"
+#include "selftest.h"
 
 /* This is a cache used by get_next_line to store the content of a
    file to be searched for file lines.  */
@@ -1136,3 +1137,118 @@ dump_location_info (FILE *stream)
   dump_labelled_location_range (stream, "AD-HOC LOCATIONS",
                                MAX_SOURCE_LOCATION + 1, UINT_MAX);
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests of location handling.  */
+
+/* Verify the result of LOCATION_FILE/LOCATION_LINE/LOCATION_COLUMN
+   on LOC.  */
+
+static void
+assert_loceq (const char *exp_filename, int exp_linenum, int exp_colnum,
+             location_t loc)
+{
+  ASSERT_STREQ (exp_filename, LOCATION_FILE (loc));
+  ASSERT_EQ (exp_linenum, LOCATION_LINE (loc));
+  ASSERT_EQ (exp_colnum, LOCATION_COLUMN (loc));
+}
+
+/* Verify basic operation of ordinary linemaps.  */
+
+static void
+test_accessing_ordinary_linemaps ()
+{
+  /* Build a simple linemap describing some locations. */
+  linemap_add (line_table, LC_ENTER, false, "foo.c", 0);
+
+  linemap_line_start (line_table, 1, 100);
+  location_t loc_a = linemap_position_for_column (line_table, 1);
+  location_t loc_b = linemap_position_for_column (line_table, 23);
+
+  linemap_line_start (line_table, 2, 100);
+  location_t loc_c = linemap_position_for_column (line_table, 1);
+  location_t loc_d = linemap_position_for_column (line_table, 17);
+
+  /* Example of a very long line.  */
+  linemap_line_start (line_table, 3, 2000);
+  location_t loc_e = linemap_position_for_column (line_table, 700);
+
+  linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+
+  /* Multiple files.  */
+  linemap_add (line_table, LC_ENTER, false, "bar.c", 0);
+  linemap_line_start (line_table, 1, 200);
+  location_t loc_f = linemap_position_for_column (line_table, 150);
+  linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+
+  /* Verify that we can recover the location info.  */
+  assert_loceq ("foo.c", 1, 1, loc_a);
+  assert_loceq ("foo.c", 1, 23, loc_b);
+  assert_loceq ("foo.c", 2, 1, loc_c);
+  assert_loceq ("foo.c", 2, 17, loc_d);
+  assert_loceq ("foo.c", 3, 700, loc_e);
+  assert_loceq ("bar.c", 1, 150, loc_f);
+
+  ASSERT_FALSE (is_location_from_builtin_token (loc_a));
+}
+
+/* Verify various properties of UNKNOWN_LOCATION.  */
+
+static void
+test_unknown_location ()
+{
+  ASSERT_EQ (NULL, LOCATION_FILE (UNKNOWN_LOCATION));
+  ASSERT_EQ (0, LOCATION_LINE (UNKNOWN_LOCATION));
+  ASSERT_EQ (0, LOCATION_COLUMN (UNKNOWN_LOCATION));
+}
+
+/* Verify various properties of BUILTINS_LOCATION.  */
+
+static void
+test_builtins ()
+{
+  assert_loceq ("<built-in>", 0, 0, BUILTINS_LOCATION);
+  ASSERT_PRED1 (is_location_from_builtin_token, BUILTINS_LOCATION);
+}
+
+/* Verify reading of input files (e.g. for caret-based diagnostics).  */
+
+static void
+test_reading_source_line ()
+{
+  /* We will read *this* source file, using __FILE__.
+     Here is some specific text to read and test for:
+     The quick brown fox jumps over the lazy dog.  */
+  const int linenum_after_test_message = __LINE__;
+  const int linenum = linenum_after_test_message - 1;
+
+  int line_size;
+  const char *source_line = location_get_source_line (__FILE__, linenum, &line_size);
+  ASSERT_TRUE (source_line != NULL);
+  ASSERT_EQ (53, line_size);
+  if (!strncmp ("     The quick brown fox jumps over the lazy dog.  */",
+              source_line, line_size))
+    ::selftest::pass (__FILE__, __LINE__,
+                     "source_line matched expected value");
+  else
+    ::selftest::fail (__FILE__, __LINE__,
+                     "source_line did not match expected value");
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+input_c_tests ()
+{
+  test_accessing_ordinary_linemaps ();
+  test_unknown_location ();
+  test_builtins ();
+  test_reading_source_line ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
diff --git a/gcc/rtl-tests.c b/gcc/rtl-tests.c
new file mode 100644 (file)
index 0000000..3e9ebae
--- /dev/null
@@ -0,0 +1,117 @@
+/* Unit tests for RTL-handling.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "rtl.h"
+#include "pretty-print.h"
+#include "cfgbuild.h"
+#include "print-rtl.h"
+#include "selftest.h"
+#include "function.h"
+#include "emit-rtl.h"
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Verify that PAT is printed as EXPECTED.  Helper function for
+   selftests.  */
+
+static void
+verify_print_pattern (const char *expected, rtx pat)
+{
+  pretty_printer pp;
+  print_pattern (&pp, pat, 1);
+  ASSERT_STREQ (expected, pp_formatted_text (&pp));
+}
+
+/* Unit testing of "single_set".  */
+
+static void
+test_single_set ()
+{
+  /* A label is not a SET.  */
+  ASSERT_EQ (NULL_RTX, single_set (gen_label_rtx ()));
+
+  /* An unconditional jump insn is a single SET.  */
+  rtx set_pc = gen_rtx_SET (pc_rtx,
+                           gen_rtx_LABEL_REF (VOIDmode,
+                                              gen_label_rtx ()));
+  rtx_insn *jump_insn = emit_jump_insn (set_pc);
+  ASSERT_EQ (set_pc, single_set (jump_insn));
+
+  /* etc */
+}
+
+/* Construct an unconditional jump to a label, and verify that
+   various properties of it are sane.  */
+
+static void
+test_uncond_jump ()
+{
+  rtx_insn *label = gen_label_rtx ();
+  rtx jump_pat = gen_rtx_SET (pc_rtx,
+                             gen_rtx_LABEL_REF (VOIDmode,
+                                                label));
+  ASSERT_EQ (SET, jump_pat->code);
+  ASSERT_EQ (LABEL_REF, SET_SRC (jump_pat)->code);
+  ASSERT_EQ (label, LABEL_REF_LABEL (SET_SRC (jump_pat)));
+  ASSERT_EQ (PC, SET_DEST (jump_pat)->code);
+
+  verify_print_pattern ("pc=L0", jump_pat);
+
+  rtx_insn *jump_insn = emit_jump_insn (jump_pat);
+  ASSERT_FALSE (any_condjump_p (jump_insn));
+  ASSERT_TRUE (any_uncondjump_p (jump_insn));
+  ASSERT_TRUE (pc_set (jump_insn));
+  ASSERT_TRUE (simplejump_p (jump_insn));
+  ASSERT_TRUE (onlyjump_p (jump_insn));
+  ASSERT_TRUE (control_flow_insn_p (jump_insn));
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+rtl_tests_c_tests ()
+{
+  test_single_set ();
+  test_uncond_jump ();
+
+  /* Purge state.  */
+  set_first_insn (NULL);
+  set_last_insn (NULL);
+}
+
+} // namespace selftest
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
new file mode 100644 (file)
index 0000000..ab334aa
--- /dev/null
@@ -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 (file)
index 0000000..de804df
--- /dev/null
@@ -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 (file)
index 0000000..a1d3074
--- /dev/null
@@ -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 */
index e4e83a5ae16eaae870b670e808bb3b3ef6dcbd69..ceb60168bf167ea00759ead506e5dbf395017670 100644 (file)
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "tree.h"
 #include "spellcheck.h"
+#include "selftest.h"
 
 /* The Levenshtein distance is an "edit-distance": the minimal
    number of one-character insertions, removals or substitutions
@@ -165,3 +166,60 @@ find_closest_string (const char *target,
 
   return best_candidate;
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests.  */
+
+/* Verify that the levenshtein_distance (A, B) equals the expected
+   value.  */
+
+static void
+levenshtein_distance_unit_test_oneway (const char *a, const char *b,
+                                      edit_distance_t expected)
+{
+  edit_distance_t actual = levenshtein_distance (a, b);
+  ASSERT_EQ (actual, expected);
+}
+
+/* Verify that both
+     levenshtein_distance (A, B)
+   and
+     levenshtein_distance (B, A)
+   equal the expected value, to ensure that the function is symmetric.  */
+
+static void
+levenshtein_distance_unit_test (const char *a, const char *b,
+                               edit_distance_t expected)
+{
+  levenshtein_distance_unit_test_oneway (a, b, expected);
+  levenshtein_distance_unit_test_oneway (b, a, expected);
+}
+
+/* Verify levenshtein_distance for a variety of pairs of pre-canned
+   inputs, comparing against known-good values.  */
+
+void
+spellcheck_c_tests ()
+{
+  levenshtein_distance_unit_test ("", "nonempty", strlen ("nonempty"));
+  levenshtein_distance_unit_test ("saturday", "sunday", 3);
+  levenshtein_distance_unit_test ("foo", "m_foo", 2);
+  levenshtein_distance_unit_test ("hello_world", "HelloWorld", 3);
+  levenshtein_distance_unit_test
+    ("the quick brown fox jumps over the lazy dog", "dog", 40);
+  levenshtein_distance_unit_test
+    ("the quick brown fox jumps over the lazy dog",
+     "the quick brown dog jumps over the lazy fox",
+     4);
+  levenshtein_distance_unit_test
+    ("Lorem ipsum dolor sit amet, consectetur adipiscing elit,",
+     "All your base are belong to us",
+     44);
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
index b68744b92f3f924a1077efc03fb822d26ac7f5a3..15a771679439c31f8742924c56b6ad86ae695164 100644 (file)
@@ -1,3 +1,10 @@
+2016-06-06  David Malcolm  <dmalcolm@redhat.com>
+
+       * 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.
+
 2016-06-06  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
 
        PR middle-end/37780
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 (file)
index ac49992..0000000
+++ /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 (file)
index 3e7dc78..0000000
+++ /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;
-}
index 321b4baafe0c2bedecfbefe3e302daa97b0f3bd3..be2ac8dcfcb7a266cf1defbe5ff732f0de4eaf50 100644 (file)
@@ -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 } \
index 230878eeff1113394c25c3b5a1e7c5df174160ce..543b8a3dc72a67c42e73673d814eeb9e4a157bb6 100644 (file)
@@ -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);
index 0beb06e8571b6a97f0bb0f429450c0bc1d3da12c..06923cf0c94e3ababebfb0f017d87c8d8a0e66ae 100644 (file)
@@ -42,6 +42,8 @@ private:
 
   void start_timevars ();
 
+  void run_self_tests ();
+
   bool m_use_TV_TOTAL;
   bool m_init_signals;
 };
index 7fc24ba7173e9c16a61ba06208d94475dbd1226e..40e524bba9c340a4ada46b582e69fac41ced51c4 100644 (file)
@@ -58,6 +58,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-cfgcleanup.h"
 #include "gimplify.h"
 #include "attribs.h"
+#include "selftest.h"
 
 /* This file contains functions for building the Control Flow Graph (CFG)
    for a function tree.  */
@@ -9195,3 +9196,280 @@ gt_pch_nx (edge_def *e, gt_pointer_operator op, void *cookie)
     op (&(e->insns.r), cookie);
   op (&(block), cookie);
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Helper function for CFG selftests: create a dummy function decl
+   and push it as cfun.  */
+
+static tree
+push_fndecl (const char *name)
+{
+  tree fn_type = build_function_type_array (integer_type_node, 0, NULL);
+  /* FIXME: this uses input_location: */
+  tree fndecl = build_fn_decl (name, fn_type);
+  tree retval = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+                           NULL_TREE, integer_type_node);
+  DECL_RESULT (fndecl) = retval;
+  push_struct_function (fndecl);
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  ASSERT_TRUE (fun != NULL);
+  init_empty_tree_cfg_for_function (fun);
+  ASSERT_EQ (2, n_basic_blocks_for_fn (fun));
+  ASSERT_EQ (0, n_edges_for_fn (fun));
+  return fndecl;
+}
+
+/* These tests directly create CFGs.
+   Compare with the static fns within tree-cfg.c:
+     - build_gimple_cfg
+     - make_blocks: calls create_basic_block (seq, bb);
+     - make_edges.   */
+
+/* Verify a simple cfg of the form:
+     ENTRY -> A -> B -> C -> EXIT.  */
+
+static void
+test_linear_chain ()
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_test_linear_chain");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+
+  /* Create some empty blocks.  */
+  basic_block bb_a = create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun));
+  basic_block bb_b = create_empty_bb (bb_a);
+  basic_block bb_c = create_empty_bb (bb_b);
+
+  ASSERT_EQ (5, n_basic_blocks_for_fn (fun));
+  ASSERT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create some edges: a simple linear chain of BBs.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), bb_a, EDGE_FALLTHRU);
+  make_edge (bb_a, bb_b, 0);
+  make_edge (bb_b, bb_c, 0);
+  make_edge (bb_c, EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+
+  /* Verify the edges.  */
+  ASSERT_EQ (4, n_edges_for_fn (fun));
+  ASSERT_EQ (NULL, ENTRY_BLOCK_PTR_FOR_FN (fun)->preds);
+  ASSERT_EQ (1, ENTRY_BLOCK_PTR_FOR_FN (fun)->succs->length ());
+  ASSERT_EQ (1, bb_a->preds->length ());
+  ASSERT_EQ (1, bb_a->succs->length ());
+  ASSERT_EQ (1, bb_b->preds->length ());
+  ASSERT_EQ (1, bb_b->succs->length ());
+  ASSERT_EQ (1, bb_c->preds->length ());
+  ASSERT_EQ (1, bb_c->succs->length ());
+  ASSERT_EQ (1, EXIT_BLOCK_PTR_FOR_FN (fun)->preds->length ());
+  ASSERT_EQ (NULL, EXIT_BLOCK_PTR_FOR_FN (fun)->succs);
+
+  /* Verify the dominance information
+     Each BB in our simple chain should be dominated by the one before
+     it.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
+  ASSERT_EQ (bb_b, get_immediate_dominator (CDI_DOMINATORS, bb_c));
+  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
+  ASSERT_EQ (1, dom_by_b.length ());
+  ASSERT_EQ (bb_c, dom_by_b[0]);
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance: each BB in our chain is post-dominated
+     by the one after it.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  ASSERT_EQ (bb_b, get_immediate_dominator (CDI_POST_DOMINATORS, bb_a));
+  ASSERT_EQ (bb_c, get_immediate_dominator (CDI_POST_DOMINATORS, bb_b));
+  vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
+  ASSERT_EQ (1, postdom_by_b.length ());
+  ASSERT_EQ (bb_a, postdom_by_b[0]);
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+/* Verify a simple CFG of the form:
+     ENTRY
+       |
+       A
+      / \
+     /t  \f
+    B     C
+     \   /
+      \ /
+       D
+       |
+      EXIT.  */
+
+static void
+test_diamond ()
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_test_diamond");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+
+  /* Create some empty blocks.  */
+  basic_block bb_a = create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun));
+  basic_block bb_b = create_empty_bb (bb_a);
+  basic_block bb_c = create_empty_bb (bb_a);
+  basic_block bb_d = create_empty_bb (bb_b);
+
+  ASSERT_EQ (6, n_basic_blocks_for_fn (fun));
+  ASSERT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create the edges.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), bb_a, EDGE_FALLTHRU);
+  make_edge (bb_a, bb_b, EDGE_TRUE_VALUE);
+  make_edge (bb_a, bb_c, EDGE_FALSE_VALUE);
+  make_edge (bb_b, bb_d, 0);
+  make_edge (bb_c, bb_d, 0);
+  make_edge (bb_d, EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+
+  /* Verify the edges.  */
+  ASSERT_EQ (6, n_edges_for_fn (fun));
+  ASSERT_EQ (1, bb_a->preds->length ());
+  ASSERT_EQ (2, bb_a->succs->length ());
+  ASSERT_EQ (1, bb_b->preds->length ());
+  ASSERT_EQ (1, bb_b->succs->length ());
+  ASSERT_EQ (1, bb_c->preds->length ());
+  ASSERT_EQ (1, bb_c->succs->length ());
+  ASSERT_EQ (2, bb_d->preds->length ());
+  ASSERT_EQ (1, bb_d->succs->length ());
+
+  /* Verify the dominance information.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
+  ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_c));
+  ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_d));
+  vec<basic_block> dom_by_a = get_dominated_by (CDI_DOMINATORS, bb_a);
+  ASSERT_EQ (3, dom_by_a.length ()); /* B, C, D, in some order.  */
+  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
+  ASSERT_EQ (0, dom_by_b.length ());
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_a));
+  ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_b));
+  ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_c));
+  vec<basic_block> postdom_by_d = get_dominated_by (CDI_POST_DOMINATORS, bb_d);
+  ASSERT_EQ (3, postdom_by_d.length ()); /* A, B, C in some order.  */
+  vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
+  ASSERT_EQ (0, postdom_by_b.length ());
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+/* Verify that we can handle a CFG containing a "complete" aka
+   fully-connected subgraph (where A B C D below all have edges
+   pointing to each other node, also to themselves).
+   e.g.:
+     ENTRY  EXIT
+       |    ^
+       |   /
+       |  /
+       | /
+       V/
+       A<--->B
+       ^^   ^^
+       | \ / |
+       |  X  |
+       | / \ |
+       VV   VV
+       C<--->D
+*/
+
+static void
+test_fully_connected ()
+{
+  gimple_register_cfg_hooks ();
+
+  tree fndecl = push_fndecl ("cfg_fully_connected");
+  function *fun = DECL_STRUCT_FUNCTION (fndecl);
+
+  const int n = 4;
+
+  /* Create some empty blocks.  */
+  auto_vec <basic_block> subgraph_nodes;
+  for (int i = 0; i < n; i++)
+    subgraph_nodes.safe_push (create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (fun)));
+
+  ASSERT_EQ (n + 2, n_basic_blocks_for_fn (fun));
+  ASSERT_EQ (0, n_edges_for_fn (fun));
+
+  /* Create the edges.  */
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (fun), subgraph_nodes[0], EDGE_FALLTHRU);
+  make_edge (subgraph_nodes[0], EXIT_BLOCK_PTR_FOR_FN (fun), 0);
+  for (int i = 0; i < n; i++)
+    for (int j = 0; j < n; j++)
+      make_edge (subgraph_nodes[i], subgraph_nodes[j], 0);
+
+  /* Verify the edges.  */
+  ASSERT_EQ (2 + (n * n), n_edges_for_fn (fun));
+  /* The first one is linked to ENTRY/EXIT as well as itself and
+     everything else.  */
+  ASSERT_EQ (n + 1, subgraph_nodes[0]->preds->length ());
+  ASSERT_EQ (n + 1, subgraph_nodes[0]->succs->length ());
+  /* The other ones in the subgraph are linked to everything in
+     the subgraph (including themselves).  */
+  for (int i = 1; i < n; i++)
+    {
+      ASSERT_EQ (n, subgraph_nodes[i]->preds->length ());
+      ASSERT_EQ (n, subgraph_nodes[i]->succs->length ());
+    }
+
+  /* Verify the dominance information.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+  /* The initial block in the subgraph should be dominated by ENTRY.  */
+  ASSERT_EQ (ENTRY_BLOCK_PTR_FOR_FN (fun),
+            get_immediate_dominator (CDI_DOMINATORS,
+                                     subgraph_nodes[0]));
+  /* Every other block in the subgraph should be dominated by the
+     initial block.  */
+  for (int i = 1; i < n; i++)
+    ASSERT_EQ (subgraph_nodes[0],
+              get_immediate_dominator (CDI_DOMINATORS,
+                                       subgraph_nodes[i]));
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Similarly for post-dominance.  */
+  calculate_dominance_info (CDI_POST_DOMINATORS);
+  /* The initial block in the subgraph should be postdominated by EXIT.  */
+  ASSERT_EQ (EXIT_BLOCK_PTR_FOR_FN (fun),
+            get_immediate_dominator (CDI_POST_DOMINATORS,
+                                     subgraph_nodes[0]));
+  /* Every other block in the subgraph should be postdominated by the
+     initial block, since that leads to EXIT.  */
+  for (int i = 1; i < n; i++)
+    ASSERT_EQ (subgraph_nodes[0],
+              get_immediate_dominator (CDI_POST_DOMINATORS,
+                                       subgraph_nodes[i]));
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  pop_cfun ();
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+tree_cfg_c_tests ()
+{
+  test_linear_chain ();
+  test_diamond ();
+  test_fully_connected ();
+}
+
+} // namespace selftest
+
+/* TODO: test the dominator/postdominator logic with various graphs/nodes:
+   - loop
+   - nested loops
+   - switch statement (a block with many out-edges)
+   - something that jumps to itself
+   - etc  */
+
+#endif /* CHECKING_P */
index 2e01eac6acacb44ec31b794830948f8cc293270b..fd0e6921bfd754c0cf9e6bd01f39b432166a6dfa 100644 (file)
@@ -61,6 +61,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "print-tree.h"
 #include "ipa-utils.h"
+#include "selftest.h"
 
 /* Tree code classes.  */
 
@@ -14203,4 +14204,65 @@ combined_fn_name (combined_fn fn)
     return internal_fn_name (as_internal_fn (fn));
 }
 
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests for tree.  */
+
+/* Verify that integer constants are sane.  */
+
+static void
+test_integer_constants ()
+{
+  ASSERT_TRUE (integer_type_node != NULL);
+  ASSERT_TRUE (build_int_cst (integer_type_node, 0) != NULL);
+
+  tree type = integer_type_node;
+
+  tree zero = build_zero_cst (type);
+  ASSERT_EQ (INTEGER_CST, TREE_CODE (zero));
+  ASSERT_EQ (type, TREE_TYPE (zero));
+
+  tree one = build_int_cst (type, 1);
+  ASSERT_EQ (INTEGER_CST, TREE_CODE (one));
+  ASSERT_EQ (type, TREE_TYPE (zero));
+}
+
+/* Verify identifiers.  */
+
+static void
+test_identifiers ()
+{
+  tree identifier = get_identifier ("foo");
+  ASSERT_EQ (3, IDENTIFIER_LENGTH (identifier));
+  ASSERT_STREQ ("foo", IDENTIFIER_POINTER (identifier));
+}
+
+/* Verify LABEL_DECL.  */
+
+static void
+test_labels ()
+{
+  tree identifier = get_identifier ("err");
+  tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
+                               identifier, void_type_node);
+  ASSERT_EQ (-1, LABEL_DECL_UID (label_decl));
+  ASSERT_FALSE (FORCED_LABEL (label_decl));
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+tree_c_tests ()
+{
+  test_integer_constants ();
+  test_identifiers ();
+  test_labels ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
+
 #include "gt-tree.h"
index a483d5b5451ec20a00a1ec6e952071a0fd3c3dae..fd200ea904bfc0414e88ff7bb9fc0174bcd1ed26 100644 (file)
--- a/gcc/vec.c
+++ b/gcc/vec.c
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "hash-table.h"
+#include "selftest.h"
 
 /* vNULL is an empty type with a template cast operation that returns
    a zero-initialized vec<T, A, L> instance.  Use this when you want
@@ -188,3 +189,194 @@ dump_vec_loc_statistics (void)
 {
   vec_mem_desc.dump (VEC_ORIGIN);
 }
+
+#ifndef GENERATOR_FILE
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests.  */
+
+/* Call V.safe_push for all ints from START up to, but not including LIMIT.
+   Helper function for selftests.  */
+
+static void
+safe_push_range (vec <int>&v, int start, int limit)
+{
+  for (int i = start; i < limit; i++)
+    v.safe_push (i);
+}
+
+/* Verify that vec::quick_push works correctly.  */
+
+static void
+test_quick_push ()
+{
+  auto_vec <int> v;
+  ASSERT_EQ (0, v.length ());
+  v.reserve (3);
+  ASSERT_EQ (0, v.length ());
+  ASSERT_TRUE (v.space (3));
+  v.quick_push (5);
+  v.quick_push (6);
+  v.quick_push (7);
+  ASSERT_EQ (3, v.length ());
+  ASSERT_EQ (5, v[0]);
+  ASSERT_EQ (6, v[1]);
+  ASSERT_EQ (7, v[2]);
+}
+
+/* Verify that vec::safe_push works correctly.  */
+
+static void
+test_safe_push ()
+{
+  auto_vec <int> v;
+  ASSERT_EQ (0, v.length ());
+  v.safe_push (5);
+  v.safe_push (6);
+  v.safe_push (7);
+  ASSERT_EQ (3, v.length ());
+  ASSERT_EQ (5, v[0]);
+  ASSERT_EQ (6, v[1]);
+  ASSERT_EQ (7, v[2]);
+}
+
+/* Verify that vec::truncate works correctly.  */
+
+static void
+test_truncate ()
+{
+  auto_vec <int> v;
+  ASSERT_EQ (0, v.length ());
+  safe_push_range (v, 0, 10);
+  ASSERT_EQ (10, v.length ());
+
+  v.truncate (5);
+  ASSERT_EQ (5, v.length ());
+}
+
+/* Verify that vec::safe_grow_cleared works correctly.  */
+
+static void
+test_safe_grow_cleared ()
+{
+  auto_vec <int> v;
+  ASSERT_EQ (0, v.length ());
+  v.safe_grow_cleared (50);
+  ASSERT_EQ (50, v.length ());
+  ASSERT_EQ (0, v[0]);
+  ASSERT_EQ (0, v[49]);
+}
+
+/* Verify that vec::pop works correctly.  */
+
+static void
+test_pop ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 5, 20);
+  ASSERT_EQ (15, v.length ());
+
+  int last = v.pop ();
+  ASSERT_EQ (19, last);
+  ASSERT_EQ (14, v.length ());
+}
+
+/* Verify that vec::safe_insert works correctly.  */
+
+static void
+test_safe_insert ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.safe_insert (5, 42);
+  ASSERT_EQ (4, v[4]);
+  ASSERT_EQ (42, v[5]);
+  ASSERT_EQ (5, v[6]);
+  ASSERT_EQ (11, v.length ());
+}
+
+/* Verify that vec::ordered_remove works correctly.  */
+
+static void
+test_ordered_remove ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.ordered_remove (5);
+  ASSERT_EQ (4, v[4]);
+  ASSERT_EQ (6, v[5]);
+  ASSERT_EQ (9, v.length ());
+}
+
+/* Verify that vec::unordered_remove works correctly.  */
+
+static void
+test_unordered_remove ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.unordered_remove (5);
+  ASSERT_EQ (9, v.length ());
+}
+
+/* Verify that vec::block_remove works correctly.  */
+
+static void
+test_block_remove ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.block_remove (5, 3);
+  ASSERT_EQ (3, v[3]);
+  ASSERT_EQ (4, v[4]);
+  ASSERT_EQ (8, v[5]);
+  ASSERT_EQ (9, v[6]);
+  ASSERT_EQ (7, v.length ());
+}
+
+/* Comparator for use by test_qsort.  */
+
+static int
+reverse_cmp (const void *p_i, const void *p_j)
+{
+  return *(const int *)p_j - *(const int *)p_i;
+}
+
+/* Verify that vec::qsort works correctly.  */
+
+static void
+test_qsort ()
+{
+  auto_vec <int> v;
+  safe_push_range (v, 0, 10);
+  v.qsort (reverse_cmp);
+  ASSERT_EQ (9, v[0]);
+  ASSERT_EQ (8, v[1]);
+  ASSERT_EQ (1, v[8]);
+  ASSERT_EQ (0, v[9]);
+  ASSERT_EQ (10, v.length ());
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+vec_c_tests ()
+{
+  test_quick_push ();
+  test_safe_push ();
+  test_truncate ();
+  test_safe_grow_cleared ();
+  test_pop ();
+  test_safe_insert ();
+  test_ordered_remove ();
+  test_unordered_remove ();
+  test_block_remove ();
+  test_qsort ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
+#endif /* #ifndef GENERATOR_FILE */
index 8648e7dc286342bc06885af11279871ef79622a9..30d355fdb8914fa9dca142a7eb72e3ab765e7098 100644 (file)
@@ -23,6 +23,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
+#include "selftest.h"
+#include "wide-int-print.h"
 
 
 #define HOST_BITS_PER_HALF_WIDE_INT 32
@@ -2144,3 +2146,171 @@ template void generic_wide_int <wide_int_ref_storage <false> >::dump () const;
 template void generic_wide_int <wide_int_ref_storage <true> >::dump () const;
 template void offset_int::dump () const;
 template void widest_int::dump () const;
+
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests for wide ints.  We run these multiple times, once per type.  */
+
+/* Helper function for building a test value.  */
+
+template <class VALUE_TYPE>
+static VALUE_TYPE
+from_int (int i);
+
+/* Specializations of the fixture for each wide-int type.  */
+
+/* Specialization for VALUE_TYPE == wide_int.  */
+
+template <>
+wide_int
+from_int (int i)
+{
+  return wi::shwi (i, 32);
+}
+
+/* Specialization for VALUE_TYPE == offset_int.  */
+
+template <>
+offset_int
+from_int (int i)
+{
+  return offset_int (i);
+}
+
+/* Specialization for VALUE_TYPE == widest_int.  */
+
+template <>
+widest_int
+from_int (int i)
+{
+  return widest_int (i);
+}
+
+/* Verify that print_dec (WI, ..., SGN) gives the expected string
+   representation (using base 10).  */
+
+static void
+assert_deceq (const char *expected, const wide_int_ref &wi, signop sgn)
+{
+  char buf[WIDE_INT_PRINT_BUFFER_SIZE];
+  print_dec (wi, buf, sgn);
+  ASSERT_STREQ (expected, buf);
+}
+
+/* Likewise for base 16.  */
+
+static void
+assert_hexeq (const char *expected, const wide_int_ref &wi)
+{
+  char buf[WIDE_INT_PRINT_BUFFER_SIZE];
+  print_hex (wi, buf);
+  ASSERT_STREQ (expected, buf);
+}
+
+/* Test cases.  */
+
+/* Verify that print_dec and print_hex work for VALUE_TYPE.  */
+
+template <class VALUE_TYPE>
+static void
+test_printing ()
+{
+  VALUE_TYPE a = from_int<VALUE_TYPE> (42);
+  assert_deceq ("42", a, SIGNED);
+  assert_hexeq ("0x2a", a);
+}
+
+/* Verify that various operations work correctly for VALUE_TYPE,
+   unary and binary, using both function syntax, and
+   overloaded-operators.  */
+
+template <class VALUE_TYPE>
+static void
+test_ops ()
+{
+  VALUE_TYPE a = from_int<VALUE_TYPE> (7);
+  VALUE_TYPE b = from_int<VALUE_TYPE> (3);
+
+  /* Using functions.  */
+  assert_deceq ("-7", wi::neg (a), SIGNED);
+  assert_deceq ("10", wi::add (a, b), SIGNED);
+  assert_deceq ("4", wi::sub (a, b), SIGNED);
+  assert_deceq ("-4", wi::sub (b, a), SIGNED);
+  assert_deceq ("21", wi::mul (a, b), SIGNED);
+
+  /* Using operators.  */
+  assert_deceq ("-7", -a, SIGNED);
+  assert_deceq ("10", a + b, SIGNED);
+  assert_deceq ("4", a - b, SIGNED);
+  assert_deceq ("-4", b - a, SIGNED);
+  assert_deceq ("21", a * b, SIGNED);
+}
+
+/* Verify that various comparisons work correctly for VALUE_TYPE.  */
+
+template <class VALUE_TYPE>
+static void
+test_comparisons ()
+{
+  VALUE_TYPE a = from_int<VALUE_TYPE> (7);
+  VALUE_TYPE b = from_int<VALUE_TYPE> (3);
+
+  /* == */
+  ASSERT_TRUE (wi::eq_p (a, a));
+  ASSERT_FALSE (wi::eq_p (a, b));
+
+  /* != */
+  ASSERT_TRUE (wi::ne_p (a, b));
+  ASSERT_FALSE (wi::ne_p (a, a));
+
+  /* < */
+  ASSERT_FALSE (wi::lts_p (a, a));
+  ASSERT_FALSE (wi::lts_p (a, b));
+  ASSERT_TRUE (wi::lts_p (b, a));
+
+  /* <= */
+  ASSERT_TRUE (wi::les_p (a, a));
+  ASSERT_FALSE (wi::les_p (a, b));
+  ASSERT_TRUE (wi::les_p (b, a));
+
+  /* > */
+  ASSERT_FALSE (wi::gts_p (a, a));
+  ASSERT_TRUE (wi::gts_p (a, b));
+  ASSERT_FALSE (wi::gts_p (b, a));
+
+  /* >= */
+  ASSERT_TRUE (wi::ges_p (a, a));
+  ASSERT_TRUE (wi::ges_p (a, b));
+  ASSERT_FALSE (wi::ges_p (b, a));
+
+  /* comparison */
+  ASSERT_EQ (-1, wi::cmps (b, a));
+  ASSERT_EQ (0, wi::cmps (a, a));
+  ASSERT_EQ (1, wi::cmps (a, b));
+}
+
+/* Run all of the selftests, using the given VALUE_TYPE.  */
+
+template <class VALUE_TYPE>
+static void run_all_wide_int_tests ()
+{
+  test_printing <VALUE_TYPE> ();
+  test_ops <VALUE_TYPE> ();
+  test_comparisons <VALUE_TYPE> ();
+}
+
+/* Run all of the selftests within this file, for all value types.  */
+
+void
+wide_int_cc_tests ()
+{
+ run_all_wide_int_tests <wide_int> ();
+ run_all_wide_int_tests <offset_int> ();
+ run_all_wide_int_tests <widest_int> ();
+}
+
+} // namespace selftest
+#endif /* CHECKING_P */