Message ID | 20171230193159.GN1833@tucnak |
---|---|
State | New |
Headers | show |
Series | Fix expand_assignment stores to CONCAT (PR middle-end/83609) | expand |
On December 30, 2017 8:31:59 PM GMT+01:00, Jakub Jelinek <jakub@redhat.com> wrote: >Hi! > >The first hunk before the if (!from...) part shows a typo I've made in >a >recent change, the last argument of simplify_gen_subreg is byte offset, >and >the subreg has same bitsize outer and inner modes, so using byte offset >1 >makes no sense at all. >Another issue that the testcase suffers from is that the >simplify_gen_rtx >(preexisting issue) can fail, and in that case trying to >read_complex_part >from that NULL will ICE. The patch tries harder by trying to simplify >the >2 halves separately, and for all cases when simplify_gen_subreg fails >which >can happen because of various reasons, there is the fallback to go >through >memory. > >Bootstrapped/regtested on x86_64-linux and i686-linux, ok for >trunk/7.3? OK. Richard. >2017-12-30 Jakub Jelinek <jakub@redhat.com> > > PR middle-end/83609 > * expr.c (expand_assignment): Fix up a typo in simplify_gen_subreg > last argument when extracting from CONCAT. If either from_real or > from_imag is NULL, use expansion through memory. If result is not > a CONCAT and simplify_gen_subreg fails, try to simplify_gen_subreg > the parts directly to inner mode, if even that fails, use expansion > through memory. > > * gcc.dg/pr83609.c: New test. > * g++.dg/opt/pr83609.C: New test. > >--- gcc/expr.c.jj 2017-12-21 09:43:19.797042465 +0100 >+++ gcc/expr.c 2017-12-30 13:49:19.634057445 +0100 >@@ -5158,7 +5158,9 @@ expand_assignment (tree to, tree from, b > from_mode, 0); > rtx from_imag > = simplify_gen_subreg (to_mode, XEXP (result, 1), >- from_mode, 1); >+ from_mode, 0); >+ if (!from_real || !from_imag) >+ goto concat_store_slow; > emit_move_insn (XEXP (to_rtx, 0), from_real); > emit_move_insn (XEXP (to_rtx, 1), from_imag); > } >@@ -5167,14 +5169,35 @@ expand_assignment (tree to, tree from, b > rtx from_rtx > = simplify_gen_subreg (GET_MODE (to_rtx), result, > TYPE_MODE (TREE_TYPE (from)), 0); >- emit_move_insn (XEXP (to_rtx, 0), >- read_complex_part (from_rtx, false)); >- emit_move_insn (XEXP (to_rtx, 1), >- read_complex_part (from_rtx, true)); >+ if (from_rtx) >+ { >+ emit_move_insn (XEXP (to_rtx, 0), >+ read_complex_part (from_rtx, false)); >+ emit_move_insn (XEXP (to_rtx, 1), >+ read_complex_part (from_rtx, true)); >+ } >+ else >+ { >+ machine_mode to_mode >+ = GET_MODE_INNER (GET_MODE (to_rtx)); >+ rtx from_real >+ = simplify_gen_subreg (to_mode, result, >+ TYPE_MODE (TREE_TYPE (from)), >+ 0); >+ rtx from_imag >+ = simplify_gen_subreg (to_mode, result, >+ TYPE_MODE (TREE_TYPE (from)), >+ GET_MODE_SIZE (to_mode)); >+ if (!from_real || !from_imag) >+ goto concat_store_slow; >+ emit_move_insn (XEXP (to_rtx, 0), from_real); >+ emit_move_insn (XEXP (to_rtx, 1), from_imag); >+ } > } > } > else > { >+ concat_store_slow:; > rtx temp = assign_stack_temp (GET_MODE (to_rtx), > GET_MODE_SIZE (GET_MODE (to_rtx))); > write_complex_part (temp, XEXP (to_rtx, 0), false); >--- gcc/testsuite/gcc.dg/pr83609.c.jj 2017-12-30 13:47:49.350044674 >+0100 >+++ gcc/testsuite/gcc.dg/pr83609.c 2017-12-30 13:42:52.227002619 +0100 >@@ -0,0 +1,29 @@ >+/* PR middle-end/83609 */ >+/* { dg-do run } */ >+/* { dg-options "-O2 -fno-tree-forwprop -fno-tree-ccp -fno-tree-fre >-fno-tree-pre -fno-code-hoisting" } */ >+ >+#if __SIZEOF_LONG_LONG__ == 2 * __SIZEOF_FLOAT__ >+_Complex float >+foo (void) >+{ >+ _Complex float c; >+ *((unsigned long long *)&c) = 0x123456789abcdef0ULL; >+ return c; >+} >+ >+int >+main () >+{ >+ union { _Complex float c; unsigned long long l; } u; >+ u.c = foo (); >+ if (u.l != 0x123456789abcdef0ULL) >+ __builtin_abort (); >+ return 0; >+} >+#else >+int >+main () >+{ >+ return 0; >+} >+#endif >--- gcc/testsuite/g++.dg/opt/pr83609.C.jj 2017-12-30 13:48:18.937048860 >+0100 >+++ gcc/testsuite/g++.dg/opt/pr83609.C 2017-12-30 13:46:25.968032868 >+0100 >@@ -0,0 +1,28 @@ >+// PR middle-end/83609 >+// { dg-do compile } >+// { dg-options "-O2 -fno-tree-forwprop" } >+ >+template <typename> class B; >+template <> struct B<float> >+{ >+ float foo () { return __real__ b; } >+ _Complex float b; >+}; >+ >+void bar (int); >+ >+template <class T> >+void >+baz () >+{ >+ B<T> h; >+ T *a = (T *) &h; >+ a[0] = a[1] = 6; >+ h.foo () ? void () : bar (7); >+} >+ >+int >+main () >+{ >+ baz<float> (); >+} > > Jakub
--- gcc/expr.c.jj 2017-12-21 09:43:19.797042465 +0100 +++ gcc/expr.c 2017-12-30 13:49:19.634057445 +0100 @@ -5158,7 +5158,9 @@ expand_assignment (tree to, tree from, b from_mode, 0); rtx from_imag = simplify_gen_subreg (to_mode, XEXP (result, 1), - from_mode, 1); + from_mode, 0); + if (!from_real || !from_imag) + goto concat_store_slow; emit_move_insn (XEXP (to_rtx, 0), from_real); emit_move_insn (XEXP (to_rtx, 1), from_imag); } @@ -5167,14 +5169,35 @@ expand_assignment (tree to, tree from, b rtx from_rtx = simplify_gen_subreg (GET_MODE (to_rtx), result, TYPE_MODE (TREE_TYPE (from)), 0); - emit_move_insn (XEXP (to_rtx, 0), - read_complex_part (from_rtx, false)); - emit_move_insn (XEXP (to_rtx, 1), - read_complex_part (from_rtx, true)); + if (from_rtx) + { + emit_move_insn (XEXP (to_rtx, 0), + read_complex_part (from_rtx, false)); + emit_move_insn (XEXP (to_rtx, 1), + read_complex_part (from_rtx, true)); + } + else + { + machine_mode to_mode + = GET_MODE_INNER (GET_MODE (to_rtx)); + rtx from_real + = simplify_gen_subreg (to_mode, result, + TYPE_MODE (TREE_TYPE (from)), + 0); + rtx from_imag + = simplify_gen_subreg (to_mode, result, + TYPE_MODE (TREE_TYPE (from)), + GET_MODE_SIZE (to_mode)); + if (!from_real || !from_imag) + goto concat_store_slow; + emit_move_insn (XEXP (to_rtx, 0), from_real); + emit_move_insn (XEXP (to_rtx, 1), from_imag); + } } } else { + concat_store_slow:; rtx temp = assign_stack_temp (GET_MODE (to_rtx), GET_MODE_SIZE (GET_MODE (to_rtx))); write_complex_part (temp, XEXP (to_rtx, 0), false); --- gcc/testsuite/gcc.dg/pr83609.c.jj 2017-12-30 13:47:49.350044674 +0100 +++ gcc/testsuite/gcc.dg/pr83609.c 2017-12-30 13:42:52.227002619 +0100 @@ -0,0 +1,29 @@ +/* PR middle-end/83609 */ +/* { dg-do run } */ +/* { dg-options "-O2 -fno-tree-forwprop -fno-tree-ccp -fno-tree-fre -fno-tree-pre -fno-code-hoisting" } */ + +#if __SIZEOF_LONG_LONG__ == 2 * __SIZEOF_FLOAT__ +_Complex float +foo (void) +{ + _Complex float c; + *((unsigned long long *)&c) = 0x123456789abcdef0ULL; + return c; +} + +int +main () +{ + union { _Complex float c; unsigned long long l; } u; + u.c = foo (); + if (u.l != 0x123456789abcdef0ULL) + __builtin_abort (); + return 0; +} +#else +int +main () +{ + return 0; +} +#endif --- gcc/testsuite/g++.dg/opt/pr83609.C.jj 2017-12-30 13:48:18.937048860 +0100 +++ gcc/testsuite/g++.dg/opt/pr83609.C 2017-12-30 13:46:25.968032868 +0100 @@ -0,0 +1,28 @@ +// PR middle-end/83609 +// { dg-do compile } +// { dg-options "-O2 -fno-tree-forwprop" } + +template <typename> class B; +template <> struct B<float> +{ + float foo () { return __real__ b; } + _Complex float b; +}; + +void bar (int); + +template <class T> +void +baz () +{ + B<T> h; + T *a = (T *) &h; + a[0] = a[1] = 6; + h.foo () ? void () : bar (7); +} + +int +main () +{ + baz<float> (); +}