From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 35788 invoked by alias); 2 Jun 2016 20:41:17 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 35727 invoked by uid 89); 2 Jun 2016 20:41:15 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.3 required=5.0 tests=BAYES_00,KAM_LAZY_DOMAIN_SECURITY,RP_MATCHES_RCVD,SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=midlevel, mid-level, Midlevel, Mid-level X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Thu, 02 Jun 2016 20:41:05 +0000 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 3CD8D186867 for ; Thu, 2 Jun 2016 20:41:04 +0000 (UTC) Received: from c64.redhat.com (vpn-237-222.phx2.redhat.com [10.3.237.222]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u52Kf2Wt007154; Thu, 2 Jun 2016 16:41:03 -0400 From: David Malcolm To: gcc-patches@gcc.gnu.org Cc: Bernd Schmidt , Jeff Law , David Malcolm Subject: [PATCH 01/16] Core of selftest framework (v6) Date: Thu, 02 Jun 2016 20:41:00 -0000 Message-Id: <1464901625-54547-2-git-send-email-dmalcolm@redhat.com> In-Reply-To: <1464901625-54547-1-git-send-email-dmalcolm@redhat.com> References: <1464874868.11895.41.camel@redhat.com> <1464901625-54547-1-git-send-email-dmalcolm@redhat.com> X-IsSubscribed: yes X-SW-Source: 2016-06/txt/msg00212.txt.bz2 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 "selftests". (all.cross): Likewise. (selftests): New phony target. (s-selftests): New target. (selftests-gdb): New phony target. (COLLECT2_OBJS): Add selftest.o. * common.opt (fself-test): New. * selftest-run-tests.c: New file. * selftest.c: New file. * selftest.h: New file. * toplev.c: Include selftest.h. (toplev::run_self_tests): New. (toplev::main): Handle -fself-test. * toplev.h (toplev::run_self_tests): New. --- gcc/Makefile.in | 31 ++++++++-- gcc/common.opt | 4 ++ gcc/selftest-run-tests.c | 76 ++++++++++++++++++++++++ gcc/selftest.c | 49 +++++++++++++++ gcc/selftest.h | 152 +++++++++++++++++++++++++++++++++++++++++++++++ gcc/toplev.c | 26 ++++++++ gcc/toplev.h | 2 + 7 files changed, 335 insertions(+), 5 deletions(-) create mode 100644 gcc/selftest-run-tests.c create mode 100644 gcc/selftest.c create mode 100644 gcc/selftest.h diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 673f87d..2c5faa3 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -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 + 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)) @@ -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 selftests # 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 selftests @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-selftests" to ensure that we only run the selftests if the +# driver or cc1 change. +.PHONY: selftests +selftests: s-selftests +s-selftests: $(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: selftests-gdb +selftests-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. diff --git a/gcc/common.opt b/gcc/common.opt index 682cb41..10a10ed 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -2057,6 +2057,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. diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c new file mode 100644 index 0000000..4233351 --- /dev/null +++ b/gcc/selftest-run-tests.c @@ -0,0 +1,76 @@ +/* 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 +. */ + +#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 (); + + /* Mid-level data structures. */ + input_c_tests (); + tree_c_tests (); + gimple_c_tests (); + rtl_tests_c_tests (); + + /* Higher-level tests, or for components that other selftests don't + rely on. */ + diagnostic_show_locus_c_tests (); + fold_const_c_tests (); + spellcheck_c_tests (); + tree_cfg_c_tests (); + + /* This one relies on most of the above. */ + function_tests_c_tests (); + + /* Finished running tests. */ + long finish_time = get_run_time (); + long elapsed_time = finish_time - start_time; + + fprintf (stderr, + "-fself-test: %i pass(es) in %ld.%06ld seconds\n", + num_passes, + elapsed_time / 1000000, elapsed_time % 1000000); +} + +#endif /* #if CHECKING_P */ diff --git a/gcc/selftest.c b/gcc/selftest.c new file mode 100644 index 0000000..cc921c8 --- /dev/null +++ b/gcc/selftest.c @@ -0,0 +1,49 @@ +/* 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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "selftest.h" + +#if CHECKING_P + +int selftest::num_passes; + +/* Record the successful outcome of some aspect of a test. */ + +void +selftest::pass (const char */*file*/, int /*line*/, const char */*msg*/) +{ + num_passes++; +} + +/* Report the failed outcome of some aspect of a test and abort. */ + +void +selftest::fail (const char *file, int line, const char *msg) +{ + fprintf (stderr, + "%s:%i: FAIL: %s\n", + file, line, msg); + /* TODO: add calling function name as well? */ + abort (); +} + +#endif /* #if CHECKING_P */ diff --git a/gcc/selftest.h b/gcc/selftest.h new file mode 100644 index 0000000..2062a8b --- /dev/null +++ b/gcc/selftest.h @@ -0,0 +1,152 @@ +/* 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 +. */ + +#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 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 */ diff --git a/gcc/toplev.c b/gcc/toplev.c index 580c03a..795818a 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.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); diff --git a/gcc/toplev.h b/gcc/toplev.h index 0beb06e..06923cf 100644 --- a/gcc/toplev.h +++ b/gcc/toplev.h @@ -42,6 +42,8 @@ private: void start_timevars (); + void run_self_tests (); + bool m_use_TV_TOTAL; bool m_init_signals; }; -- 1.8.5.3