diff mbox

[7/9] combine.c selftests

Message ID 1473381053-18817-8-git-send-email-dmalcolm@redhat.com
State New
Headers show

Commit Message

David Malcolm Sept. 9, 2016, 12:30 a.m. UTC
gcc/ChangeLog:
	* combine.c: Include selftest.h and selftest-rtl.h.
	(try_combine): Add assertion on this_basic_block.
	(class selftest::combine_test): New subclass of
	selftest::tl_dump_test.
	(selftest::combine_test::combine_test): New ctor.
	(selftest::test_combining_shifts): New function.
	(selftest::test_non_combinable_shifts): New function.
	(selftest::combine_c_tests): New function.
	* selftest-run-tests.c (selftest::run_tests): Run
	selftest::combine_c_tests.
	* selftest.h (selftest::combine_c_tests): New decl.
---
 gcc/combine.c            | 155 +++++++++++++++++++++++++++++++++++++++++++++++
 gcc/selftest-run-tests.c |   1 +
 gcc/selftest.h           |   1 +
 3 files changed, 157 insertions(+)

Comments

Jeff Law Sept. 16, 2016, 8:40 p.m. UTC | #1
On 09/08/2016 06:30 PM, David Malcolm wrote:
> gcc/ChangeLog:
> 	* combine.c: Include selftest.h and selftest-rtl.h.
> 	(try_combine): Add assertion on this_basic_block.
> 	(class selftest::combine_test): New subclass of
> 	selftest::tl_dump_test.
> 	(selftest::combine_test::combine_test): New ctor.
> 	(selftest::test_combining_shifts): New function.
> 	(selftest::test_non_combinable_shifts): New function.
> 	(selftest::combine_c_tests): New function.
> 	* selftest-run-tests.c (selftest::run_tests): Run
> 	selftest::combine_c_tests.
> 	* selftest.h (selftest::combine_c_tests): New decl.
> diff --git a/gcc/combine.c b/gcc/combine.c
> index 1b262f9..9c148bb 100644
> --- a/gcc/combine.c
> +++ b/gcc/combine.c
> @@ -2625,6 +2627,8 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
>    rtx new_other_notes;
>    int i;
>
> +  gcc_assert (this_basic_block);
Presumably when you set up the self test the first time this was NULL :-)

> +
> +/* combine_test's constructor.  Write DUMP_CONTENT to a tempfile and load
> +   it.  Initialize df and perform dataflow analysis.  */
> +
> +combine_test::combine_test (const char *dump_content,
> +			    int dumped_first_pseudo_regno)
> +: rtl_dump_test (dump_content, dumped_first_pseudo_regno),
> +  m_df_test ()
> +{
> +  /* The dataflow instance should have been created by m_df_test's ctor.  */
> +  gcc_assert (df);
> +
> +  /* From rest_of_handle_combine.  */
> +  df_set_flags (/*DF_LR_RUN_DCE + */ DF_DEFER_INSN_RESCAN);
> +  df_note_add_problem ();
> +  df_analyze ();
> +}
So rather than taking a string (which is a pain to construct), then 
writing it out to a file, then reading it in, what's wrong with having 
RTL fragments in a file?


Jeff
David Malcolm Sept. 16, 2016, 9:31 p.m. UTC | #2
On Fri, 2016-09-16 at 14:40 -0600, Jeff Law wrote:
> On 09/08/2016 06:30 PM, David Malcolm wrote:
> > gcc/ChangeLog:
> > 	* combine.c: Include selftest.h and selftest-rtl.h.
> > 	(try_combine): Add assertion on this_basic_block.
> > 	(class selftest::combine_test): New subclass of
> > 	selftest::tl_dump_test.
> > 	(selftest::combine_test::combine_test): New ctor.
> > 	(selftest::test_combining_shifts): New function.
> > 	(selftest::test_non_combinable_shifts): New function.
> > 	(selftest::combine_c_tests): New function.
> > 	* selftest-run-tests.c (selftest::run_tests): Run
> > 	selftest::combine_c_tests.
> > 	* selftest.h (selftest::combine_c_tests): New decl.
> > diff --git a/gcc/combine.c b/gcc/combine.c
> > index 1b262f9..9c148bb 100644
> > --- a/gcc/combine.c
> > +++ b/gcc/combine.c
> > @@ -2625,6 +2627,8 @@ try_combine (rtx_insn *i3, rtx_insn *i2,
> > rtx_insn *i1, rtx_insn *i0,
> >    rtx new_other_notes;
> >    int i;
> > 
> > +  gcc_assert (this_basic_block);
> Presumably when you set up the self test the first time this was NULL
> :-)

Indeed :)

> > +
> > +/* combine_test's constructor.  Write DUMP_CONTENT to a tempfile
> > and load
> > +   it.  Initialize df and perform dataflow analysis.  */
> > +
> > +combine_test::combine_test (const char *dump_content,
> > +			    int dumped_first_pseudo_regno)
> > +: rtl_dump_test (dump_content, dumped_first_pseudo_regno),
> > +  m_df_test ()
> > +{
> > +  /* The dataflow instance should have been created by m_df_test's
> > ctor.  */
> > +  gcc_assert (df);
> > +
> > +  /* From rest_of_handle_combine.  */
> > +  df_set_flags (/*DF_LR_RUN_DCE + */ DF_DEFER_INSN_RESCAN);
> > +  df_note_add_problem ();
> > +  df_analyze ();
> > +}
> So rather than taking a string (which is a pain to construct), then 
> writing it out to a file, then reading it in, what's wrong with
> having 
> RTL fragments in a file?
> 

I plan to rework these fixtures so that they can accept both string
fragments and filenames.
diff mbox

Patch

diff --git a/gcc/combine.c b/gcc/combine.c
index 1b262f9..9c148bb 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -102,6 +102,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "valtrack.h"
 #include "rtl-iter.h"
 #include "print-rtl.h"
+#include "selftest.h"
+#include "selftest-rtl.h"
 
 #ifndef LOAD_EXTEND_OP
 #define LOAD_EXTEND_OP(M) UNKNOWN
@@ -2625,6 +2627,8 @@  try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
   rtx new_other_notes;
   int i;
 
+  gcc_assert (this_basic_block);
+
   /* Immediately return if any of I0,I1,I2 are the same insn (I3 can
      never be).  */
   if (i1 == i2 || i0 == i2 || (i0 && i0 == i1))
@@ -14441,3 +14445,154 @@  make_pass_combine (gcc::context *ctxt)
 {
   return new pass_combine (ctxt);
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* A subclass of rtl_dump_test for testing combine.c.  */
+
+class combine_test : public rtl_dump_test
+{
+ public:
+   combine_test (const char *dump_content, int dumped_first_pseudo_regno);
+
+ private:
+   dataflow_test m_df_test;
+};
+
+/* combine_test's constructor.  Write DUMP_CONTENT to a tempfile and load
+   it.  Initialize df and perform dataflow analysis.  */
+
+combine_test::combine_test (const char *dump_content,
+			    int dumped_first_pseudo_regno)
+: rtl_dump_test (dump_content, dumped_first_pseudo_regno),
+  m_df_test ()
+{
+  /* The dataflow instance should have been created by m_df_test's ctor.  */
+  gcc_assert (df);
+
+  /* From rest_of_handle_combine.  */
+  df_set_flags (/*DF_LR_RUN_DCE + */ DF_DEFER_INSN_RESCAN);
+  df_note_add_problem ();
+  df_analyze ();
+}
+
+/* Verify that combine_instructions works, for combining a pair of shifts.
+   Ideally we'd test try_combine by itself, but a fair amount of
+   refactoring would be needed to do so.  */
+
+static void
+test_combining_shifts ()
+{
+  /* Taken from
+       gcc/testsuite/gcc.dg/asr_div1.c -O2 -fdump-rtl-all -mtune=cortex-a53
+     for aarch64, hand editing the prev/next insns to 0 as needed, and
+     editing whitespace to avoid over-long lines.  */
+  const char *input_dump
+    = ("(insn 8 0 9 2 (set (reg:DI 78)\n"
+       "        (lshiftrt:DI (reg:DI 76)\n"
+       "            (const_int 32 [0x20])))\n"
+       "        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14\n"
+       "        641 {*aarch64_lshr_sisd_or_int_di3}\n"
+       "     (expr_list:REG_DEAD (reg:DI 76)\n"
+       "        (nil)))\n"
+       "(insn 9 8 0 2 (set (reg:SI 79)\n"
+       "        (ashiftrt:SI (subreg:SI (reg:DI 78) 0)\n"
+       "            (const_int 3 [0x3])))\n"
+       "        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14\n"
+       "        642 {*aarch64_ashr_sisd_or_int_si3}\n"
+       "     (expr_list:REG_DEAD (reg:DI 78)\n"
+       "        (nil)))\n");
+  combine_test t (input_dump, 76);
+
+  rtx_insn *insn_8 = get_insn_by_uid (8);
+  ASSERT_TRUE (insn_8);
+
+  rtx_insn *insn_9 = get_insn_by_uid (9);
+  ASSERT_TRUE (insn_9);
+
+  int rebuild_jump_labels_after_combine
+    = combine_instructions (get_insns (), max_reg_num ());
+  ASSERT_FALSE (rebuild_jump_labels_after_combine);
+
+  /* Verify that insns 8 and 9 were combined.  */
+  ASSERT_EQ (1, combine_merges);
+
+  /* insn 8 should now be deleted.  */
+  ASSERT_EQ (NOTE, GET_CODE (insn_8));
+  ASSERT_EQ (NOTE_INSN_DELETED, NOTE_KIND (insn_8));
+
+  /* insn 9 should now be a shift of 35.
+     On aarch64 it's a set; on x86_64 it's a parallel of a set and a clobber
+     of CC.  */
+  rtx set_in_9 = single_set (insn_9);
+  ASSERT_TRUE (set_in_9);
+  rtx src_of_9 = SET_SRC (set_in_9);
+  ASSERT_EQ (ASHIFTRT, GET_CODE (src_of_9));
+  rtx amt = XEXP (src_of_9, 1);
+  ASSERT_TRUE (CONST_INT_P (amt));
+  ASSERT_EQ (35, INTVAL (amt));
+}
+
+/* Test of failing to combine instructions.
+
+   Similar to test_combining_shifts, but with the input register
+   for the 2nd shift hand-edited (from 78 to 80) so that it doesn't come
+   from the output of the 1st shift, so that the shifts should *not*
+   be combinable.  */
+
+static void
+test_non_combinable_shifts ()
+{
+  const char *input_dump
+    = ("(insn 8 0 9 2 (set (reg:DI 78)\n"
+       "        (lshiftrt:DI (reg:DI 76)\n"
+       "            (const_int 32 [0x20])))\n"
+       "        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14\n"
+       "        641 {*aarch64_lshr_sisd_or_int_di3}\n"
+       "     (expr_list:REG_DEAD (reg:DI 76)\n"
+       "        (nil)))\n"
+       "(insn 9 8 0 2 (set (reg:SI 79)\n"
+       "        (ashiftrt:SI (subreg:SI (reg:DI 80) 0)\n"
+       "            (const_int 3 [0x3])))\n"
+       "        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14\n"
+       "        642 {*aarch64_ashr_sisd_or_int_si3}\n"
+       "     (expr_list:REG_DEAD (reg:DI 78)\n"
+       "        (nil)))\n");
+  combine_test t (input_dump, 76);
+
+  rtx_insn *insn_8 = get_insn_by_uid (8);
+  ASSERT_TRUE (insn_8);
+
+  rtx_insn *insn_9 = get_insn_by_uid (9);
+  ASSERT_TRUE (insn_9);
+
+  int rebuild_jump_labels_after_combine
+    = combine_instructions (get_insns (), max_reg_num ());
+  ASSERT_FALSE (rebuild_jump_labels_after_combine);
+
+  /* Verify that no insns were combined.  */
+  ASSERT_EQ (0, combine_merges);
+
+  /* insn 8 should not have be touched.  */
+  ASSERT_EQ (INSN, GET_CODE (insn_8));
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+combine_c_tests ()
+{
+  /* Only run these tests for i386.  */
+#ifndef I386_OPTS_H
+  return;
+#endif
+
+  test_combining_shifts ();
+  test_non_combinable_shifts ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index 14e5828..296fe00 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -68,6 +68,7 @@  selftest::run_tests ()
 
   /* Higher-level tests, or for components that other selftests don't
      rely on.  */
+  combine_c_tests ();
   diagnostic_show_locus_c_tests ();
   diagnostic_c_tests ();
   edit_context_c_tests ();
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 037a5ee..8b94c3a 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -190,6 +190,7 @@  extern void forcibly_ggc_collect ();
 /* Declarations for specific families of tests (by source file), in
    alphabetical order.  */
 extern void bitmap_c_tests ();
+extern void combine_c_tests ();
 extern void df_core_c_tests ();
 extern void diagnostic_c_tests ();
 extern void diagnostic_show_locus_c_tests ();