This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Add x86_64-specific selftests for RTL function reader (v2)
- From: David Malcolm <dmalcolm at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org, Uros Bizjak <ubizjak at gmail dot com>, Jan Hubicka <hubicka at ucw dot cz>
- Cc: Bernd Schmidt <bschmidt at redhat dot com>, David Malcolm <dmalcolm at redhat dot com>
- Date: Mon, 19 Dec 2016 12:12:44 -0500
- Subject: [PATCH] Add x86_64-specific selftests for RTL function reader (v2)
- Authentication-results: sourceware.org; auth=none
- References: <1480644013-3660-4-git-send-email-dmalcolm@redhat.com>
Note to i386 maintainters: this patch is part of the RTL frontend.
It adds selftests for verifying that the RTL dump reader works as
expected, with a mixture of real and hand-written "dumps" to
exercise various aspects of the loader. Many RTL dumps contain
target-specific features (e.g. names of hard regs), and so these
selftests need to be target-specific, and hence this patch puts
them in i386.c.
Tested on i686-pc-linux-gnu and x86_64-pc-linux-gnu.
OK for trunk, assuming bootstrap®rtest?
(this is dependent on patch 8a within the kit).
Changed in v2:
- fixed selftest failures on i686:
* config/i386/i386.c
(selftest::ix86_test_loading_dump_fragment_1): Fix handling of
"frame" reg.
(selftest::ix86_test_loading_call_insn): Require TARGET_SSE.
- updated to use "<3>" syntax for pseudos, rather than "$3"
Blurb from v1:
This patch adds more selftests for class function_reader, where
the dumps to be read contain x86_64-specific features.
In an earlier version of the patch kit, these were handled using
preprocessor conditionals.
This version instead runs them via a target hook for running
target-specific selftests, thus putting them within i386.c.
gcc/ChangeLog:
* config/i386/i386.c
(selftest::ix86_test_loading_dump_fragment_1): New function.
(selftest::ix86_test_loading_call_insn): New function.
(selftest::ix86_test_loading_full_dump): New function.
(selftest::ix86_test_loading_unspec): New function.
(selftest::ix86_run_selftests): Call the new functions.
gcc/testsuite/ChangeLog:
* selftests/x86_64: New subdirectory.
* selftests/x86_64/call-insn.rtl: New file.
* selftests/x86_64/copy-hard-reg-into-frame.rtl: New file.
* selftests/x86_64/times-two.rtl: New file.
* selftests/x86_64/unspec.rtl: New file.
---
gcc/config/i386/i386.c | 210 +++++++++++++++++++++
gcc/testsuite/selftests/x86_64/call-insn.rtl | 17 ++
.../selftests/x86_64/copy-hard-reg-into-frame.rtl | 15 ++
gcc/testsuite/selftests/x86_64/times-two.rtl | 51 +++++
gcc/testsuite/selftests/x86_64/unspec.rtl | 20 ++
5 files changed, 313 insertions(+)
create mode 100644 gcc/testsuite/selftests/x86_64/call-insn.rtl
create mode 100644 gcc/testsuite/selftests/x86_64/copy-hard-reg-into-frame.rtl
create mode 100644 gcc/testsuite/selftests/x86_64/times-two.rtl
create mode 100644 gcc/testsuite/selftests/x86_64/unspec.rtl
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 1cd1cd8..dc1a86f 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -51200,6 +51200,209 @@ ix86_test_dumping_memory_blockage ()
" ] UNSPEC_MEMORY_BLOCKAGE)))\n", pat, &r);
}
+/* Verify loading an RTL dump; specifically a dump of copying
+ a param on x86_64 from a hard reg into the frame.
+ This test is target-specific since the dump contains target-specific
+ hard reg names. */
+
+static void
+ix86_test_loading_dump_fragment_1 ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION,
+ locate_file ("x86_64/copy-hard-reg-into-frame.rtl"));
+
+ rtx_insn *insn = get_insn_by_uid (1);
+
+ /* The block structure and indentation here is purely for
+ readability; it mirrors the structure of the rtx. */
+ tree mem_expr;
+ {
+ rtx pat = PATTERN (insn);
+ ASSERT_EQ (SET, GET_CODE (pat));
+ {
+ rtx dest = SET_DEST (pat);
+ ASSERT_EQ (MEM, GET_CODE (dest));
+ /* Verify the "/c" was parsed. */
+ ASSERT_TRUE (RTX_FLAG (dest, call));
+ ASSERT_EQ (SImode, GET_MODE (dest));
+ {
+ rtx addr = XEXP (dest, 0);
+ ASSERT_EQ (PLUS, GET_CODE (addr));
+ ASSERT_EQ (DImode, GET_MODE (addr));
+ {
+ rtx lhs = XEXP (addr, 0);
+ /* Verify that the "frame" REG was consolidated. */
+ ASSERT_RTX_PTR_EQ (frame_pointer_rtx, lhs);
+ }
+ {
+ rtx rhs = XEXP (addr, 1);
+ ASSERT_EQ (CONST_INT, GET_CODE (rhs));
+ ASSERT_EQ (-4, INTVAL (rhs));
+ }
+ }
+ /* Verify the "[1 i+0 S4 A32]" was parsed. */
+ ASSERT_EQ (1, MEM_ALIAS_SET (dest));
+ /* "i" should have been handled by synthesizing a global int
+ variable named "i". */
+ mem_expr = MEM_EXPR (dest);
+ ASSERT_NE (mem_expr, NULL);
+ ASSERT_EQ (VAR_DECL, TREE_CODE (mem_expr));
+ ASSERT_EQ (integer_type_node, TREE_TYPE (mem_expr));
+ ASSERT_EQ (IDENTIFIER_NODE, TREE_CODE (DECL_NAME (mem_expr)));
+ ASSERT_STREQ ("i", IDENTIFIER_POINTER (DECL_NAME (mem_expr)));
+ /* "+0". */
+ ASSERT_TRUE (MEM_OFFSET_KNOWN_P (dest));
+ ASSERT_EQ (0, MEM_OFFSET (dest));
+ /* "S4". */
+ ASSERT_EQ (4, MEM_SIZE (dest));
+ /* "A32. */
+ ASSERT_EQ (32, MEM_ALIGN (dest));
+ }
+ {
+ rtx src = SET_SRC (pat);
+ ASSERT_EQ (REG, GET_CODE (src));
+ ASSERT_EQ (SImode, GET_MODE (src));
+ ASSERT_EQ (5, REGNO (src));
+ tree reg_expr = REG_EXPR (src);
+ /* "i" here should point to the same var as for the MEM_EXPR. */
+ ASSERT_EQ (reg_expr, mem_expr);
+ }
+ }
+}
+
+/* Verify that the RTL loader copes with a call_insn dump.
+ This test is target-specific since the dump contains a target-specific
+ hard reg name. */
+
+static void
+ix86_test_loading_call_insn ()
+{
+ /* The test dump includes register "xmm0", where requires TARGET_SSE
+ to exist. */
+ if (!TARGET_SSE)
+ return;
+
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("x86_64/call-insn.rtl"));
+
+ rtx_insn *insn = get_insns ();
+ ASSERT_EQ (CALL_INSN, GET_CODE (insn));
+
+ /* "/j". */
+ ASSERT_TRUE (RTX_FLAG (insn, jump));
+
+ rtx pat = PATTERN (insn);
+ ASSERT_EQ (CALL, GET_CODE (SET_SRC (pat)));
+
+ /* Verify REG_NOTES. */
+ {
+ /* "(expr_list:REG_CALL_DECL". */
+ ASSERT_EQ (EXPR_LIST, GET_CODE (REG_NOTES (insn)));
+ rtx_expr_list *note0 = as_a <rtx_expr_list *> (REG_NOTES (insn));
+ ASSERT_EQ (REG_CALL_DECL, REG_NOTE_KIND (note0));
+
+ /* "(expr_list:REG_EH_REGION (const_int 0 [0])". */
+ rtx_expr_list *note1 = note0->next ();
+ ASSERT_EQ (REG_EH_REGION, REG_NOTE_KIND (note1));
+
+ ASSERT_EQ (NULL, note1->next ());
+ }
+
+ /* Verify CALL_INSN_FUNCTION_USAGE. */
+ {
+ /* "(expr_list:DF (use (reg:DF 21 xmm0))". */
+ rtx_expr_list *usage
+ = as_a <rtx_expr_list *> (CALL_INSN_FUNCTION_USAGE (insn));
+ ASSERT_EQ (EXPR_LIST, GET_CODE (usage));
+ ASSERT_EQ (DFmode, GET_MODE (usage));
+ ASSERT_EQ (USE, GET_CODE (usage->element ()));
+ ASSERT_EQ (NULL, usage->next ());
+ }
+}
+
+/* Verify that the RTL loader copes a dump from print_rtx_function.
+ This test is target-specific since the dump contains target-specific
+ hard reg names. */
+
+static void
+ix86_test_loading_full_dump ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("x86_64/times-two.rtl"));
+
+ ASSERT_STREQ ("times_two", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
+
+ rtx_insn *insn_1 = get_insn_by_uid (1);
+ ASSERT_EQ (NOTE, GET_CODE (insn_1));
+
+ rtx_insn *insn_7 = get_insn_by_uid (7);
+ ASSERT_EQ (INSN, GET_CODE (insn_7));
+ ASSERT_EQ (PARALLEL, GET_CODE (PATTERN (insn_7)));
+
+ rtx_insn *insn_15 = get_insn_by_uid (15);
+ ASSERT_EQ (INSN, GET_CODE (insn_15));
+ ASSERT_EQ (USE, GET_CODE (PATTERN (insn_15)));
+
+ /* Verify crtl->return_rtx. */
+ ASSERT_EQ (REG, GET_CODE (crtl->return_rtx));
+ ASSERT_EQ (0, REGNO (crtl->return_rtx));
+ ASSERT_EQ (SImode, GET_MODE (crtl->return_rtx));
+}
+
+/* Verify that the RTL loader copes with UNSPEC and UNSPEC_VOLATILE insns.
+ In particular, verify that it correctly loads the 2nd operand.
+ This test is target-specific since these are machine-specific
+ operands (and enums). */
+
+static void
+ix86_test_loading_unspec ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("x86_64/unspec.rtl"));
+
+ ASSERT_STREQ ("test_unspec", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
+
+ ASSERT_TRUE (cfun);
+
+ /* Test of an UNSPEC. */
+ rtx_insn *insn = get_insns ();
+ ASSERT_EQ (INSN, GET_CODE (insn));
+ rtx set = single_set (insn);
+ ASSERT_NE (NULL, set);
+ rtx dst = SET_DEST (set);
+ ASSERT_EQ (MEM, GET_CODE (dst));
+ rtx src = SET_SRC (set);
+ ASSERT_EQ (UNSPEC, GET_CODE (src));
+ ASSERT_EQ (BLKmode, GET_MODE (src));
+ ASSERT_EQ (UNSPEC_MEMORY_BLOCKAGE, XINT (src, 1));
+
+ rtx v0 = XVECEXP (src, 0, 0);
+
+ /* Verify that the two uses of the first SCRATCH have pointer
+ equality. */
+ rtx scratch_a = XEXP (dst, 0);
+ ASSERT_EQ (SCRATCH, GET_CODE (scratch_a));
+
+ rtx scratch_b = XEXP (v0, 0);
+ ASSERT_EQ (SCRATCH, GET_CODE (scratch_b));
+
+ ASSERT_EQ (scratch_a, scratch_b);
+
+ /* Verify that the two mems are thus treated as equal. */
+ ASSERT_TRUE (rtx_equal_p (dst, v0));
+
+ /* Verify the the insn is recognized. */
+ ASSERT_NE(-1, recog_memoized (insn));
+
+ /* Test of an UNSPEC_VOLATILE, which has its own enum values. */
+ insn = NEXT_INSN (insn);
+ ASSERT_EQ (INSN, GET_CODE (insn));
+
+ set = single_set (insn);
+ ASSERT_NE (NULL, set);
+
+ src = SET_SRC (set);
+ ASSERT_EQ (UNSPEC_VOLATILE, GET_CODE (src));
+ ASSERT_EQ (UNSPECV_RDTSCP, XINT (src, 1));
+}
+
/* Run all target-specific selftests. */
static void
@@ -51207,6 +51410,13 @@ ix86_run_selftests (void)
{
ix86_test_dumping_hard_regs ();
ix86_test_dumping_memory_blockage ();
+
+ /* Various tests of loading RTL dumps, here because they contain
+ ix86-isms (e.g. names of hard regs). */
+ ix86_test_loading_dump_fragment_1 ();
+ ix86_test_loading_call_insn ();
+ ix86_test_loading_full_dump ();
+ ix86_test_loading_unspec ();
}
} // namespace selftest
diff --git a/gcc/testsuite/selftests/x86_64/call-insn.rtl b/gcc/testsuite/selftests/x86_64/call-insn.rtl
new file mode 100644
index 0000000..8f3a781
--- /dev/null
+++ b/gcc/testsuite/selftests/x86_64/call-insn.rtl
@@ -0,0 +1,17 @@
+(function "test"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (ccall_insn/j 1
+ (set (reg:DF xmm0)
+ (call (mem:QI (symbol_ref:DI ("sqrt") [flags 0x41] <function_decl 0x7f82b1429d00 sqrt>) [0 __builtin_sqrt S1 A8])
+ (const_int 0))) "test.c":19
+ (expr_list:REG_CALL_DECL (symbol_ref:DI ("sqrt") [flags 0x41] <function_decl 0x7f82b1429d00 sqrt>)
+ (expr_list:REG_EH_REGION (const_int 0)
+ (nil)))
+ (expr_list:DF (use (reg:DF xmm0))
+ (nil)))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function "test"
diff --git a/gcc/testsuite/selftests/x86_64/copy-hard-reg-into-frame.rtl b/gcc/testsuite/selftests/x86_64/copy-hard-reg-into-frame.rtl
new file mode 100644
index 0000000..4598a1c
--- /dev/null
+++ b/gcc/testsuite/selftests/x86_64/copy-hard-reg-into-frame.rtl
@@ -0,0 +1,15 @@
+(function "copy_hard_reg_into_frame"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cinsn 1 (set (mem/c:SI
+ (plus:DI
+ (reg/f:DI frame)
+ (const_int -4))
+ [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "test.c":2
+ (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/x86_64/times-two.rtl b/gcc/testsuite/selftests/x86_64/times-two.rtl
new file mode 100644
index 0000000..8cec47a
--- /dev/null
+++ b/gcc/testsuite/selftests/x86_64/times-two.rtl
@@ -0,0 +1,51 @@
+;; Dump of this C function:
+;;
+;; int times_two (int i)
+;; {
+;; return i * 2;
+;; }
+;;
+;; after expand for target==x86_64
+
+(function "times_two"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 4 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/times-two.c":2
+ (nil))
+ (cnote 3 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 6 (set (reg:SI <2>)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/times-two.c":3
+ (nil))
+ (cinsn 7 (parallel [
+ (set (reg:SI <0> [ _2 ])
+ (ashift:SI (reg:SI <2>)
+ (const_int 1)))
+ (clobber (reg:CC flags))
+ ]) "../../src/times-two.c":3
+ (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (const_int 1))
+ (nil)))
+ (cinsn 10 (set (reg:SI <1> [ <retval> ])
+ (reg:SI <0> [ _2 ])) "../../src/times-two.c":3
+ (nil))
+ (cinsn 14 (set (reg/i:SI ax)
+ (reg:SI <1> [ <retval> ])) "../../src/times-two.c":4
+ (nil))
+ (cinsn 15 (use (reg/i:SI ax)) "../../src/times-two.c":4
+ (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "times_two"
diff --git a/gcc/testsuite/selftests/x86_64/unspec.rtl b/gcc/testsuite/selftests/x86_64/unspec.rtl
new file mode 100644
index 0000000..ac822ac
--- /dev/null
+++ b/gcc/testsuite/selftests/x86_64/unspec.rtl
@@ -0,0 +1,20 @@
+(function "test_unspec"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cinsn 1 (set (mem/v:BLK (0|scratch:DI) [0 A8])
+ (unspec:BLK [
+ (mem/v:BLK (reuse_rtx 0) [0 A8])
+ ] UNSPEC_MEMORY_BLOCKAGE)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2
+ (nil))
+
+ (cinsn 2 (set (mem/v:BLK (1|scratch:DI) [0 A8])
+ (unspec_volatile:BLK [
+ (mem/v:BLK (reuse_rtx 1) [0 A8])
+ ] UNSPECV_RDTSCP)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2
+ (nil))
+
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
--
1.8.5.3