@@ -1543,13 +1543,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
+ hash-table.o file-find.o selftest.o
# This lists all host objects for the front ends.
ALL_HOST_FRONTEND_OBJS = $(foreach v,$(CONFIG_LANGUAGES),$($(v)_OBJS))
@@ -1986,7 +1987,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.
@@ -2057,6 +2057,10 @@ fselective-scheduling2
Common Report Var(flag_selective_scheduling2) Optimization
Run selective scheduling after reload.
+fself-test
+Common 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.
new file mode 100644
@@ -0,0 +1,152 @@
+/* A self-testing framework, for use by -fself-test.
+ Copyright (C) 2015 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
+
+using namespace selftest;
+
+/* Helper function for ::selftest::run_all_tests. */
+
+static int
+test_comparator (const void *p1, const void *p2)
+{
+ const test *t1 = *static_cast<const test * const *> (p1);
+ const test *t2 = *static_cast<const test * const *> (p2);
+ return strcmp (t1->get_name (), t2->get_name ());
+}
+
+/* Locate and run all tests.
+ Return the number of failures that occurred. */
+
+int
+selftest::run_all_tests ()
+{
+ /* Create all the tests, in an arbitrary order (based on
+ the order of construction of the global "registrator" instances). */
+ runner r;
+ auto_vec<test *> tests;
+ for (registrator *iter = registrator::get_first ();
+ iter;
+ iter = iter->get_next ())
+ {
+ test *t = iter->make (&r);
+ tests.safe_push (t);
+ }
+
+ /* Sort the tests into a predictable order. */
+ tests.qsort (test_comparator);
+
+ /* Run all the tests, in order. */
+ unsigned i;
+ test *t;
+ FOR_EACH_VEC_ELT (tests, i, t)
+ {
+ r.begin_test (t);
+ t->run ();
+ r.end_test (t);
+ }
+
+ /* Cleanup. */
+ FOR_EACH_VEC_ELT (tests, i, t)
+ delete t;
+
+ return r.get_num_failures ();
+}
+
+/* Implementation of class ::selftest::runner. */
+
+/* ::selftest::runner's constructor. */
+
+runner::runner ()
+: m_passes (0),
+ m_failures (0)
+{
+}
+
+/* ::selftest::runner's destructor. */
+
+runner::~runner ()
+{
+ fprintf (stderr, "NOTE: %i pass(es); %i failure(s)\n",
+ m_passes, m_failures);
+}
+
+/* Notify the user that a particular test is about to be run. */
+
+void
+runner::begin_test (test *t)
+{
+ fprintf (stderr, "NOTE: %s: test starting\n", t->get_name ());
+}
+
+/* Record and report the successful outcome of some aspect of a test. */
+
+void
+runner::pass (const char *file, int line, test *t, const char *msg)
+{
+ fprintf (stderr, "%s:%i: PASS: %s: %s\n", file, line, t->get_name (), msg);
+ m_passes++;
+}
+
+/* Record and report the failed outcome of some aspect of a test. */
+
+void
+runner::fail (const char *file, int line, test *t, const char *msg)
+{
+ fprintf (stderr, "%s:%i: FAIL: %s: %s\n", file, line, t->get_name (), msg);
+ m_failures++;
+}
+
+/* Notify the user that a particular test has finished running. */
+
+void
+runner::end_test (test *t)
+{
+ fprintf (stderr, "NOTE: %s: test ending\n", t->get_name ());
+}
+
+/* Implementation of class ::selftest::registrator. */
+
+/* This constructor is run before main; to avoid relying on
+ anything, it simply builds a singly-linked list of
+ instances. */
+
+registrator::registrator (registrator::callback cb)
+: m_cb (cb), m_next (NULL)
+{
+ if (first)
+ {
+ /* Add this to the front of the list. */
+ m_next = first;
+ first = this;
+ }
+ else
+ first = this;
+}
+
+/* The singleton head of the registrator linked list. */
+
+registrator *registrator::first;
+
+#endif /* #if CHECKING_P */
new file mode 100644
@@ -0,0 +1,264 @@
+/* A self-testing framework, for use by -fself-test.
+ Copyright (C) 2015 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 {
+
+class test;
+class runner;
+class registrator;
+
+/* The entrypoint for running all tests. */
+
+extern int run_all_tests ();
+
+/* The class ::selftest::runner is responsible for gathering results,
+ and for output. */
+
+class runner
+{
+public:
+ runner ();
+ ~runner ();
+
+ void begin_test (test *t);
+ void pass (const char *file, int line, test *t, const char *msg);
+ void fail (const char *file, int line, test *t, const char *msg);
+ void end_test (test *t);
+
+ int get_num_failures () const { return m_failures; }
+
+private:
+ int m_passes;
+ int m_failures;
+};
+
+/* The class ::selftest::test is a base class from which specific
+ tests inherit, via the TEST and TEST_F macros below. */
+
+class test
+{
+ public:
+ virtual ~test () {}
+ virtual void run () = 0;
+
+ const char *get_name () const { return m_name; }
+
+ void set_name (const char *name) { m_name = name; }
+ void set_runner (runner *r) { m_runner = r; }
+
+ protected:
+ void pass (const char *file, int line, const char *msg)
+ {
+ m_runner->pass (file, line, this, msg);
+ }
+ void fail (const char *file, int line, const char *msg)
+ {
+ m_runner->fail (file, line, this, msg);
+ }
+
+ /* We don't yet implement setup & teardown hooks. */
+
+ private:
+ const char *m_name;
+ runner *m_runner;
+};
+
+/* An implementation detail of automatic test registration.
+ Global instances are created via the REGISTER_TEST below.
+ The constructor runs before main, wiring them up into a
+ singly-linked list, which can be traversed by
+ ::selftest::run_all_tests. */
+
+class registrator
+{
+ public:
+ typedef test *(*callback) (runner *r);
+ registrator (callback cb);
+
+ static registrator *get_first () { return first; }
+ registrator *get_next () const { return m_next; }
+
+ test *make (runner *r) const { return m_cb (r); }
+
+ private:
+ callback m_cb;
+ registrator *m_next;
+ static registrator *first;
+};
+
+} /* end of namespace selftest. */
+
+/* Macros for creating test functions. */
+
+/* Define a new test, expecting a braced function body to follow.
+ The function body becomes the implementation of a "run" method of
+ a new ::selftest::test subclass, which will be instantiated and run
+ by RUN_ALL_TESTS. */
+
+#define TEST(TEST_CASE_NAME, TEST_NAME) \
+ IMPL_TEST_SUBCLASS (TEST_CASE_NAME ## _ ## TEST_NAME, \
+ ::selftest::test, \
+ (#TEST_CASE_NAME "." #TEST_NAME) )
+
+
+/* As per TEST above, but inheriting from a fixture subclass, rather
+ than directly from ::selftest::test. */
+
+#define TEST_F(FIXTURE_CLASS_NAME, TEST_NAME) \
+ IMPL_TEST_SUBCLASS (FIXTURE_CLASS_NAME ## _ ## TEST_NAME, \
+ FIXTURE_CLASS_NAME, \
+ (#FIXTURE_CLASS_NAME "." #TEST_NAME) )
+
+/* Macros for writing tests. */
+
+/* Evaluate EXPR and coerce to bool, issuing PASS if it is true,
+ FAIL if it false. */
+
+#define EXPECT_TRUE(EXPR) \
+ SELFTEST_BEGIN_STMT \
+ const char *desc = "EXPECT_TRUE (" #EXPR ")"; \
+ bool actual = (EXPR); \
+ if (actual) \
+ pass (__FILE__, __LINE__, desc); \
+ else \
+ fail (__FILE__, __LINE__, desc); \
+ SELFTEST_END_STMT
+
+/* Evaluate EXPR and coerce to bool, issuing PASS if it is false,
+ FAIL if it true. */
+
+#define EXPECT_FALSE(EXPR) \
+ SELFTEST_BEGIN_STMT \
+ const char *desc = "EXPECT_FALSE (" #EXPR ")"; \
+ bool actual = (EXPR); \
+ if (actual) \
+ fail (__FILE__, __LINE__, desc); \
+ else \
+ pass (__FILE__, __LINE__, desc); \
+ SELFTEST_END_STMT
+
+/* Evaluate EXPECTED and ACTUAL and compare them with ==, issuing PASS
+ if they are equal, FAIL if they are non-equal. */
+
+#define EXPECT_EQ(EXPECTED, ACTUAL) \
+ SELFTEST_BEGIN_STMT \
+ const char *desc = "EXPECT_EQ (" #EXPECTED ", " #ACTUAL ")"; \
+ if ((EXPECTED) == (ACTUAL)) \
+ pass (__FILE__, __LINE__, desc); \
+ else \
+ fail (__FILE__, __LINE__, desc); \
+ SELFTEST_END_STMT
+
+/* Evaluate EXPECTED and ACTUAL and compare them with !=, issuing PASS
+ if they are non-equal, FAIL if they are equal. */
+
+#define EXPECT_NE(EXPECTED, ACTUAL) \
+ SELFTEST_BEGIN_STMT \
+ const char *desc = "EXPECT_NE (" #EXPECTED ", " #ACTUAL ")"; \
+ if ((EXPECTED) != (ACTUAL)) \
+ pass (__FILE__, __LINE__, desc); \
+ else \
+ fail (__FILE__, __LINE__, desc); \
+ SELFTEST_END_STMT
+
+/* Evaluate EXPECTED and ACTUAL and compare them with strcmp, issuing
+ PASS if they are equal, FAIL if they are non-equal. */
+
+#define EXPECT_STREQ(EXPECTED, ACTUAL) \
+ SELFTEST_BEGIN_STMT \
+ const char *desc = "EXPECT_STREQ (" #EXPECTED ", " #ACTUAL ")"; \
+ const char *expected_ = (EXPECTED); \
+ const char *actual_ = (ACTUAL); \
+ if (0 == strcmp (expected_, actual_)) \
+ pass (__FILE__, __LINE__, desc); \
+ else \
+ fail (__FILE__, __LINE__, desc); \
+ SELFTEST_END_STMT
+
+/* Evaluate PRED1 (VAL1), issuing PASS if it is true, FAIL if
+ it false. */
+
+#define EXPECT_PRED1(PRED1, VAL1) \
+ SELFTEST_BEGIN_STMT \
+ const char *desc = "EXPECT_PRED1 (" #PRED1 ", " #VAL1 ")"; \
+ bool actual = (PRED1) (VAL1); \
+ if (actual) \
+ pass (__FILE__, __LINE__, desc); \
+ else \
+ fail (__FILE__, __LINE__, desc); \
+ SELFTEST_END_STMT
+
+/* As per EXPECT_TRUE, but immediately end the test (via return) if
+ if fails. */
+
+#define ASSERT_TRUE(EXPR) \
+ SELFTEST_BEGIN_STMT \
+ const char *desc = "ASSERT_TRUE (" #EXPR ")"; \
+ bool actual = (EXPR); \
+ if (actual) \
+ pass (__FILE__, __LINE__, desc); \
+ else \
+ { \
+ fail (__FILE__, __LINE__, desc); \
+ return; \
+ } \
+ SELFTEST_END_STMT
+
+/* The remaining macros are implementation details, for internal use. */
+
+/* A macro for registering a test subclass, by creating a global object
+ with a non-trivial ctor. */
+
+#define REGISTER_TEST(SUBCLASSNAME) \
+ static selftest::registrator registrator_for_ ##SUBCLASSNAME(&SUBCLASSNAME::make)
+
+/* This macro is used to implement TEST and TEST_F. It creates a new
+ subclass of ::selftest::test, and begins the definition of a "run"
+ method for the subclass, expecting a braced method body to follow. */
+
+#define IMPL_TEST_SUBCLASS(SUBCLASS_NAME, BASE_CLASS, NAME) \
+ class SUBCLASS_NAME : public BASE_CLASS \
+ { \
+ public: \
+ void run (); \
+ static ::selftest::test *make (::selftest::runner *r) \
+ { \
+ ::selftest::test *t = new SUBCLASS_NAME (); \
+ t->set_name (NAME); \
+ t->set_runner (r); \
+ return t; \
+ } \
+ }; \
+ REGISTER_TEST(SUBCLASS_NAME); \
+ void SUBCLASS_NAME::run ()
+
+#define SELFTEST_BEGIN_STMT do {
+#define SELFTEST_END_STMT } while (0)
+
+#endif /* #if CHECKING_P */
+
+#endif /* GCC_SELFTEST_H */
@@ -87,6 +87,10 @@ along with GCC; see the file COPYING3. If not see
#include "xcoffout.h" /* Needed for external data declarations. */
#endif
+#include "selftest.h"
+
+#include <new>
+
static void general_init (const char *, bool);
static void do_compile ();
static void process_options (void);
@@ -2031,6 +2035,54 @@ toplev::start_timevars ()
timevar_start (TV_TOTAL);
}
+/* For some tests, there's a natural source file to place them in.
+ For others, they can live in their own "foo-tests.c" file.
+ Ideally, these "foo-tests.c" files would be added to OBJS in
+ Makefile.in.
+ Unfortunately, due to this bug in GNU ld
+ https://sourceware.org/bugzilla/show_bug.cgi?id=20152
+ such tests don't get run if they are linked into libbackend.a;
+ the linker appears to be discarding the global "registrator"
+ instances in files which are purely test cases. It appears
+ to work if the .o files are linked directly into cc1 (rather
+ than via libbackend.a).
+
+ Hence as a workaround, we instead directly include the files here. */
+
+#if CHECKING_P
+
+#include "function-tests.c"
+#include "hash-map-tests.c"
+#include "hash-set-tests.c"
+#include "rtl-tests.c"
+
+#endif /* #if CHECKING_P */
+
+/* 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. */
+ int result = ::selftest::run_all_tests ();
+
+ /* Ensure that a test failure leads to the process exiting with
+ a non-zero exit code. */
+ if (result)
+ error ("at least one test failure occurred");
+
+ /* Cleanup. */
+ bitmap_obstack_release (NULL);
+#else
+ sorry ("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 +2150,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;
};