Commit d9b950dd by David Malcolm Committed by David Malcolm

Selftest framework

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
parent dbc6221f
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
......
......@@ -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.
......
......@@ -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"
......@@ -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.
......
......@@ -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 */
......@@ -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 */
......@@ -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 */
/* 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 */
......@@ -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 */
/* 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 */
/* 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 */
......@@ -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 */
/* 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 */
/* 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 */
/* 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 */
/* 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 */
......@@ -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 */
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
......
/* Placeholder C source file for unit-testing gcc/spellcheck.c. */
/* { dg-do compile } */
/* { dg-options "-O" } */
int
main (int argc, char **argv)
{
return 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;
}
......@@ -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 } \
......
......@@ -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);
......
......@@ -42,6 +42,8 @@ private:
void start_timevars ();
void run_self_tests ();
bool m_use_TV_TOTAL;
bool m_init_signals;
};
......
......@@ -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 */
......@@ -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"
......@@ -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 */
......@@ -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 */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment