This patch starts adding selftests to simplify-rtx.c, to ensure that RTL expressions are simplified as we expect.
It adds a new ASSERT_RTX_EQ macro that checks for pointer equality of two rtx values. If they're non-equal, it aborts, printing both expressions. For example: ../../src/gcc/simplify-rtx.c:6354: test_binary: FAIL: ASSERT_RTL_EQ (b, simplify_rtx (gen_rtx_IOR (DImode, a, gen_rtx_AND (DImode, a, b)))) expected=0x7ff38a32ab58: (reg:DI 1 x1) actual=0x7ff38a32ab40: (reg:DI 0 x0) Successfully bootstrapped®rtested on x86_64-pc-linux-gnu Successful -fself-test of stage1 on powerpc-ibm-aix7.1.3.0 (gcc111). Successful -fself-test of gcc stage 1 on 197 out of 198 configurations in contrib/config-list.mk (the 1 failure is an unrelated build failure). OK for trunk? gcc/ChangeLog: * Makefile.in (OBJS): Add selftest-rtl.o. * selftest-rtl.c: New file. * selftest-run-tests.c (selftest::run_tests): Add call to simplify_rtx_c_tests. * selftest.c (selftest::begin_fail): New function. (selftest::fail): Reimplement in terms of begin_fail. (selftest::fail_formatted): Likewise. * selftest.h (selftest::begin_fail): New declaration. (selftest::assert_rtx_eq): New declaration. (selftest::simplify_rtx_c_tests): New declaration. (ASSERT_RTX_EQ): New macro. * simplify-rtx.c: Include selftest.h. (selftest::test_sign_bits): New function. (selftest::test_unary): New function. (selftest::test_binary): New function. (selftest::test_ternary): New function. (selftest::run_tests_for_mode): New function. (selftest::simplify_rtx_c_tests): New function. --- gcc/Makefile.in | 1 + gcc/selftest-rtl.c | 55 +++++++++++++++++++++ gcc/selftest-run-tests.c | 1 + gcc/selftest.c | 17 +++++-- gcc/selftest.h | 22 +++++++++ gcc/simplify-rtx.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 gcc/selftest-rtl.c diff --git a/gcc/Makefile.in b/gcc/Makefile.in index ca7b1f6..de085b0 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1416,6 +1416,7 @@ OBJS = \ sel-sched-ir.o \ sel-sched-dump.o \ sel-sched.o \ + selftest-rtl.o \ selftest-run-tests.o \ sese.o \ shrink-wrap.o \ diff --git a/gcc/selftest-rtl.c b/gcc/selftest-rtl.c new file mode 100644 index 0000000..e44e720 --- /dev/null +++ b/gcc/selftest-rtl.c @@ -0,0 +1,55 @@ +/* Selftest support for RTL. + Copyright (C) 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" +#include "backend.h" +#include "target.h" +#include "rtl.h" + +#if CHECKING_P + +/* Implementation detail of ASSERT_RTX_EQ. If val_expected and val_actual + fail pointer-equality, print the location, "FAIL: ", and print the + mismatching RTL expressions to stderr, then abort. */ + +void +selftest::assert_rtx_eq (const location &loc, + const char *desc_expected, const char *desc_actual, + rtx val_expected, rtx val_actual) +{ + if (val_expected == val_actual) + ::selftest::pass (loc, "ASSERT_RTL_EQ"); + else + { + ::selftest::begin_fail (loc); + fprintf (stderr, "ASSERT_RTL_EQ (%s, %s)\n", + desc_expected, desc_actual); + fprintf (stderr, " expected=%p:\n ", (void *)val_expected); + print_rtl (stderr, val_expected); + fprintf (stderr, "\n actual=%p:\n ", (void *)val_actual); + print_rtl (stderr, val_actual); + fprintf (stderr, "\n"); + abort (); + } +} + +#endif /* #if CHECKING_P */ diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c index bddf0b2..cd2883d 100644 --- a/gcc/selftest-run-tests.c +++ b/gcc/selftest-run-tests.c @@ -55,6 +55,7 @@ selftest::run_tests () tree_c_tests (); gimple_c_tests (); rtl_tests_c_tests (); + simplify_rtx_c_tests (); /* Higher-level tests, or for components that other selftests don't rely on. */ diff --git a/gcc/selftest.c b/gcc/selftest.c index ed6e517..af2b3f6 100644 --- a/gcc/selftest.c +++ b/gcc/selftest.c @@ -26,6 +26,16 @@ along with GCC; see the file COPYING3. If not see int selftest::num_passes; +/* Implementation detail of various failure handlers. Print + the location, followed by "FAIL: ". */ + +void +selftest::begin_fail (const location &loc) +{ + fprintf (stderr, "%s:%i: %s: FAIL: ", loc.m_file, loc.m_line, + loc.m_function); +} + /* Record the successful outcome of some aspect of a test. */ void @@ -39,8 +49,8 @@ selftest::pass (const location &/*loc*/, const char */*msg*/) void selftest::fail (const location &loc, const char *msg) { - fprintf (stderr,"%s:%i: %s: FAIL: %s\n", loc.m_file, loc.m_line, - loc.m_function, msg); + begin_fail (loc); + fprintf (stderr, "%s\n", msg); abort (); } @@ -51,8 +61,7 @@ selftest::fail_formatted (const location &loc, const char *fmt, ...) { va_list ap; - fprintf (stderr, "%s:%i: %s: FAIL: ", loc.m_file, loc.m_line, - loc.m_function); + begin_fail (loc); va_start (ap, fmt); vfprintf (stderr, fmt, ap); va_end (ap); diff --git a/gcc/selftest.h b/gcc/selftest.h index c6becdd..2b76850 100644 --- a/gcc/selftest.h +++ b/gcc/selftest.h @@ -63,12 +63,23 @@ extern void fail (const location &loc, const char *msg); extern void fail_formatted (const location &loc, const char *fmt, ...) ATTRIBUTE_PRINTF_2; +/* Implementation detail of various failure handlers. Print + the location, followed by "FAIL: ". */ + +extern void begin_fail (const location &loc); + /* Implementation detail of ASSERT_STREQ. */ extern void assert_streq (const location &loc, const char *desc_expected, const char *desc_actual, const char *val_expected, const char *val_actual); +/* Implementation detail of ASSERT_RTX_EQ. */ + +extern void assert_rtx_eq (const location &loc, + const char *desc_expected, const char *desc_actual, + rtx val_expected, rtx val_actual); + /* Declarations for specific families of tests (by source file), in alphabetical order. */ extern void bitmap_c_tests (); @@ -84,6 +95,7 @@ extern void hash_set_tests_c_tests (); extern void input_c_tests (); extern void pretty_print_c_tests (); extern void rtl_tests_c_tests (); +extern void simplify_rtx_c_tests (); extern void spellcheck_c_tests (); extern void spellcheck_tree_c_tests (); extern void tree_c_tests (); @@ -183,6 +195,16 @@ extern int num_passes; ::selftest::fail (SELFTEST_LOCATION, desc); \ SELFTEST_END_STMT +/* Evaluate rtx EXPECTED and ACTUAL and compare them (by pointer equality), + calling ::selftest::pass if they are equal, aborting if they are + non-equal. */ + +#define ASSERT_RTX_EQ(EXPECTED, ACTUAL) \ + SELFTEST_BEGIN_STMT \ + ::selftest::assert_rtx_eq (SELFTEST_LOCATION, #EXPECTED, #ACTUAL, \ + (EXPECTED), (ACTUAL)); \ + SELFTEST_END_STMT + #define SELFTEST_BEGIN_STMT do { #define SELFTEST_END_STMT } while (0) diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index a23a6f5..4ef342a 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-core.h" #include "varasm.h" #include "flags.h" +#include "selftest.h" /* Simplification and canonicalization of RTL. */ @@ -170,6 +171,29 @@ val_signbit_known_clear_p (machine_mode mode, unsigned HOST_WIDE_INT val) val &= (unsigned HOST_WIDE_INT) 1 << (width - 1); return val == 0; } + +#if CHECKING_P + +namespace selftest { + +/* Verify that the various *_signbit_p functions work correctly. */ + +static void +test_sign_bits () +{ + ASSERT_FALSE (val_signbit_p (QImode, 0)); + ASSERT_TRUE (val_signbit_p (QImode, 0x80)); + + ASSERT_FALSE (val_signbit_known_set_p (SImode, 0)); + ASSERT_TRUE (val_signbit_known_clear_p (SImode, 0)); + ASSERT_TRUE (val_signbit_known_set_p (SImode, 0xffffffff)); + ASSERT_FALSE (val_signbit_known_clear_p (SImode, 0xffffffff)); +} + +} // namespace selftest + +#endif /* #if CHECKING_P */ + /* Make a binary operation by properly ordering the operands and seeing if the expression folds. */ @@ -6296,3 +6320,105 @@ simplify_rtx (const_rtx x) } return NULL; } + +#if CHECKING_P + +namespace selftest { + +/* Verify that simplify_rtx works correctly on various unary expressions. */ + +static void +test_unary (machine_mode mode) +{ + /* (not (not reg)) -> reg. */ + rtx reg = gen_rtx_REG (mode, 0); + rtx expr = gen_rtx_NOT (mode, gen_rtx_NOT (mode, reg)); + ASSERT_RTX_EQ (reg, simplify_rtx (expr)); +} + +/* Verify that simplify_rtx works correctly on various binary expressions. */ + +static void +test_binary (machine_mode mode) +{ + rtx a = gen_rtx_REG (mode, 0); + rtx b = gen_rtx_REG (mode, 1); + /* (A & B) | A -> A. */ + ASSERT_RTX_EQ (a, + simplify_rtx (gen_rtx_IOR (mode, gen_rtx_AND (mode, a, b), + a))); + + /* A | (A & B) -> A. */ + ASSERT_RTX_EQ (a, + simplify_rtx (gen_rtx_IOR (mode, a, + gen_rtx_AND (mode, a, b)))); + + if (!HONOR_SIGNED_ZEROS (mode) && CONST0_RTX(mode)) + { + /* (A + 0) -> A. */ + ASSERT_RTX_EQ (a, + simplify_rtx (gen_rtx_PLUS (mode, a, CONST0_RTX(mode)))); + + /* Currently this doesn't work for complex modes. */ + if (!COMPLEX_MODE_P (mode)) + /* (0 + A) -> A. */ + ASSERT_RTX_EQ (a, + simplify_rtx (gen_rtx_PLUS (mode, CONST0_RTX(mode), a))); + } + +} + +/* Verify that simplify_rtx works correctly on various ternary expressions. */ + +static void +test_ternary (machine_mode mode) +{ + rtx a = gen_rtx_REG (mode, 0); + rtx b = gen_rtx_REG (mode, 1); + rtx c = gen_rtx_REG (mode, 2); + + /* (1 ? a : b) -> a. */ + ASSERT_RTX_EQ (a, + simplify_rtx (gen_rtx_IF_THEN_ELSE (mode, + const1_rtx, a, b))); + + /* (0 ? a : b) -> b. */ + ASSERT_RTX_EQ (b, + simplify_rtx (gen_rtx_IF_THEN_ELSE (mode, + const0_rtx, a, b))); + + /* (c ? a : a) -> a. */ + ASSERT_RTX_EQ (a, + simplify_rtx (gen_rtx_IF_THEN_ELSE (mode, + c, a, a))); +} + +/* Run all tests of simplify_rtx, using the given mode. */ + +static void +run_tests_for_mode (machine_mode mode) +{ + test_unary (mode); + test_binary (mode); + test_ternary (mode); +} + +/* Run all of the selftests within this file. */ + +void +simplify_rtx_c_tests () +{ + test_sign_bits (); + + /* Run run_tests_for_mode for every machine mode available on the + target. */ + for (int i = VOIDmode; i < NUM_MACHINE_MODES; i++) + { + machine_mode mode = (machine_mode)i; + run_tests_for_mode (mode); + } +} + +} // namespace selftest + +#endif /* CHECKING_P */ -- 1.8.5.3