Ping:
https://gcc.gnu.org/ml/gcc-patches/2016-12/msg01616.html
(the patch has been successfully bootstrap®rtested on
x86_64-pc-linux-gnu, and also tested on i686-pc-linux-gnu).
On Mon, 2016-12-19 at 12:12 -0500, David Malcolm wrote:
> 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