This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] simplify-rtx.c: start adding selftests (v2)
- From: David Malcolm <dmalcolm at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org, Richard Sandiford <rdsandiford at googlemail dot com>
- Cc: David Malcolm <dmalcolm at redhat dot com>
- Date: Wed, 6 Jul 2016 15:30:36 -0400
- Subject: [PATCH] simplify-rtx.c: start adding selftests (v2)
- Authentication-results: sourceware.org; auth=none
- References: <87zipyr6hl.fsf@googlemail.com>
On Sun, 2016-07-03 at 18:12 +0100, Richard Sandiford wrote:
> David Malcolm <dmalcolm@redhat.com> writes:
> > 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.
>
> This might be a bit confusing when more tests are added, since
> pointer
> equality is only useful in certain specific cases (e.g. when you know
> you're dealing with CONST_INTs or pseudo registers). How about
> making
> ASSERT_RTX_EQ check for rtx_equal_p equality and have something like
> ASSERT_RTX_PTR_EQ for cases where pointer equality really is needed?
> Also, how about using LAST_VIRTUAL_REGISTER + 1 as the base for
> register numbers? DImode might not be valid for register 0 on
> all targets.
Thanks. Here's an updated version which adds both ASSERT_RTX_EQ
and ASSERT_RTX_PTR_EQ. The simplify-rtx.c tests can use the
stricter pointer equality test, so I updated them to use
ASSERT_RTX_PTR_EQ condition.
I added a selftest::make_test_reg to allocate pseudo regs, starting
at LAST_VIRTUAL_REGISTER + 1.
Successfully bootstrapped®rtested on x86_64-pc-linux-gnu
OK for trunk if it passes config-list.mk testing?
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::assert_rtx_ptr_eq): New declaration.
(selftest::simplify_rtx_c_tests): New declaration.
(ASSERT_RTX_EQ): New macro.
(ASSERT_RTX_PTR_EQ): New macro.
* simplify-rtx.c: Include selftest.h.
(selftest::make_test_reg): New function.
(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 | 85 +++++++++++++++++++++++++++++
gcc/selftest-run-tests.c | 1 +
gcc/selftest.c | 17 ++++--
gcc/selftest.h | 39 ++++++++++++++
gcc/simplify-rtx.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 277 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..20f4c21
--- /dev/null
+++ b/gcc/selftest-rtl.c
@@ -0,0 +1,85 @@
+/* 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
+
+/* Helper function for selftest::assert_rtx_eq and selftest::assert_rtx_ptr_eq.
+ Print VAL_EXPECTED and VAL_ACTUAL to stderr. */
+
+static void
+print_non_equal_rtx (rtx val_expected, rtx val_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");
+}
+
+/* Implementation detail of ASSERT_RTX_EQ. If val_expected and val_actual
+ fail rtx_equal_p, 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 (rtx_equal_p (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);
+ print_non_equal_rtx (val_expected, val_actual);
+ abort ();
+ }
+}
+
+/* Implementation detail of ASSERT_RTX_PTR_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_ptr_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_PTR_EQ");
+ else
+ {
+ ::selftest::begin_fail (loc);
+ fprintf (stderr, "ASSERT_RTL_PTR_EQ (%s, %s)\n",
+ desc_expected, desc_actual);
+ print_non_equal_rtx (val_expected, val_actual);
+ 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..e133989 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -63,12 +63,30 @@ 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);
+
+/* Implementation detail of ASSERT_RTX_PTR_EQ. */
+
+extern void assert_rtx_ptr_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 +102,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 +202,26 @@ extern int num_passes;
::selftest::fail (SELFTEST_LOCATION, desc); \
SELFTEST_END_STMT
+/* Evaluate rtx EXPECTED and ACTUAL and compare them (using rtx_equal_p),
+ 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
+
+/* 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_PTR_EQ(EXPECTED, ACTUAL) \
+ SELFTEST_BEGIN_STMT \
+ ::selftest::assert_rtx_ptr_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..db3c4eb 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,117 @@ simplify_rtx (const_rtx x)
}
return NULL;
}
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Make a pseudo REG for use by selftests. */
+
+static rtx
+make_test_reg (machine_mode mode)
+{
+ static int test_reg_num = LAST_VIRTUAL_REGISTER + 1;
+
+ return gen_rtx_REG (mode, test_reg_num++);
+}
+
+/* Verify that simplify_rtx works correctly on various unary expressions. */
+
+static void
+test_unary (machine_mode mode)
+{
+ /* (not (not reg)) -> reg. */
+ rtx reg = make_test_reg (mode);
+ rtx expr = gen_rtx_NOT (mode, gen_rtx_NOT (mode, reg));
+ ASSERT_RTX_PTR_EQ (reg, simplify_rtx (expr));
+}
+
+/* Verify that simplify_rtx works correctly on various binary expressions. */
+
+static void
+test_binary (machine_mode mode)
+{
+ rtx a = make_test_reg (mode);
+ rtx b = make_test_reg (mode);
+ /* (A & B) | A -> A. */
+ ASSERT_RTX_PTR_EQ (a,
+ simplify_rtx (gen_rtx_IOR (mode, gen_rtx_AND (mode, a, b),
+ a)));
+
+ /* A | (A & B) -> A. */
+ ASSERT_RTX_PTR_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_PTR_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_PTR_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 = make_test_reg (mode);
+ rtx b = make_test_reg (mode);
+ rtx c = make_test_reg (mode);
+
+ /* (1 ? a : b) -> a. */
+ ASSERT_RTX_PTR_EQ (a,
+ simplify_rtx (gen_rtx_IF_THEN_ELSE (mode,
+ const1_rtx, a, b)));
+
+ /* (0 ? a : b) -> b. */
+ ASSERT_RTX_PTR_EQ (b,
+ simplify_rtx (gen_rtx_IF_THEN_ELSE (mode,
+ const0_rtx, a, b)));
+
+ /* (c ? a : a) -> a. */
+ ASSERT_RTX_PTR_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