The current selftest code is adequate for testing individual instructions, but most interesting passes have logic involving the interaction of multiple instructions, or require a CFG and function to be runnable. In theory we could write selftests by programatically constructing a function and CFG "by hand" via API calls, but this is awkward, tedious, and the resulting code is unnatural. Examples can be seen in function-tests.c; that file constructs trivial 3-block functions, and is pushing the limits of what I'd want to write "by hand".
This patch kit provides a more natural way to write RTL selftests, by providing a parser for RTL dumps (or fragments of RTL dumps). You can copy and paste fragments of RTL dump into the source for a pass and then have selftests that run part of the pass on that dump, asserting that desired outcomes occur. This is an updated and rewritten version of the RTL frontend work I posted in May (c.f. "[PATCH 0/4] RFC: RTL frontend" https://gcc.gnu.org/ml/gcc-patches/2016-05/msg00352.html). In that patch kit, I introduced an rtl1 frontend, capable of parsing RTL dumps, and running just one RTL pass on them, in the hope of better testing individual RTL passes. This patch kit takes a somewhat different approach: it provides the infrastructure for parsing RTL dumps, but doesn't wire it up as a frontend. Instead, it just provides a set of classes for use when writing selftests. It would be possible to build out an "rtl1" frontend as a followup to this kit. The advantage of this approach is that it's possible to run and test passes at finer granularity: for example, rather than being limited to testing all of, say, pass "final", we can also write tests that run just final_scan_insn on individual rtx_insn *, and verify that the expected output is emitted. Tests can be written at various different levels, testing how the components of a pass handle fragments of an insn, how they handle entire insns, basic blocks, and so on up to running a whole pass on a whole function. The disadvantage is that changing a selftest requires recompilation of cc1 (though that drawback affects selftests in general). An overview of the kit follows; patches 6-9 are probably the most interesting, as they show example of the kinds of selftest that can be written using this approach: * Patch 1 tidies up some global state in .md parsing, wrapping it up in an rtx_reader class. * Patches 2-4 add some selftest support code. * Patch 5 introduces a function_reader subclass of patch 1's rtx_reader, capable of parsing RTL function dumps (or fragments thereof), and generalizes things so that rtx parsing can be run from the host, rather than just at build time. * Patch 6 uses the infrastructure to write a dataflow selftest. It's a trivial example, but hopefully shows how more interesting selftests could be written. (it's much easier to write a selftest if a similar one already exists) * Patch 7 does the same, but for combine.c. * Patch 8 does the same, but for final.c, showing examples of both assembling an entire function, and of assembling individual rtx_insn * (to exercise the .md files and asm output code) * Patch 9 does the same, but for cse.c. I attempted to create a selftest that directly reproduces PR 71779, though I haven't yet been able to to reproduce the issue (just load the insns and run cse on them). These tests are very target-specific and were developed mostly for target==x86_64, and a little for target==aarch64. I put clauses like this in the various test functions, which is a kludge: /* Only run these tests for i386. */ #ifndef I386_OPTS_H return; #endif Is there a better way to express this condition? (I guess I could add a selftest::target_is_x86_p () predicate). Posting for comment (doesn't fully bootstrap yet due to a few stray warnings). Patches 1-4 could probably be applicable even without the rest of the kit. Thoughts? David Malcolm (9): Introduce class rtx_reader Add selftest::read_file selftest.h: add temp_override fixture Expose forcibly_ggc_collect and run it after all selftests Introduce class function_reader df selftests combine.c selftests final.c selftests cse.c selftests gcc/Makefile.in | 5 + gcc/cfgexpand.c | 7 +- gcc/combine.c | 155 ++++++ gcc/cse.c | 109 +++++ gcc/df-core.c | 77 +++ gcc/emit-rtl.c | 70 ++- gcc/emit-rtl.h | 2 + gcc/errors.c | 23 +- gcc/errors.h | 13 + gcc/final.c | 271 +++++++++++ gcc/function-tests.c | 2 +- gcc/function.c | 41 +- gcc/function.h | 4 +- gcc/genconstants.c | 3 +- gcc/genenums.c | 3 +- gcc/genmddeps.c | 3 +- gcc/genpreds.c | 9 +- gcc/gensupport.c | 29 +- gcc/gensupport.h | 6 +- gcc/ggc-tests.c | 28 +- gcc/print-rtl.c | 4 +- gcc/read-md.c | 328 +++++++++---- gcc/read-md.h | 192 ++++++-- gcc/read-rtl-function.c | 1197 ++++++++++++++++++++++++++++++++++++++++++++++ gcc/read-rtl-function.h | 29 ++ gcc/read-rtl.c | 760 ++++++++++++++++++++++++++++- gcc/rtl.h | 4 + gcc/selftest-rtl.c | 81 ++++ gcc/selftest-rtl.h | 66 +++ gcc/selftest-run-tests.c | 11 + gcc/selftest.c | 60 +++ gcc/selftest.h | 46 ++ gcc/tree-dfa.c | 5 + 33 files changed, 3410 insertions(+), 233 deletions(-) create mode 100644 gcc/read-rtl-function.c create mode 100644 gcc/read-rtl-function.h create mode 100644 gcc/selftest-rtl.c create mode 100644 gcc/selftest-rtl.h -- 1.8.5.3