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