On Fri, 28 Oct 2016, Jakub Jelinek wrote:

> On Fri, Oct 28, 2016 at 01:32:22AM -0600, Jeff Law wrote:
> > >I think so.  I'll leave the rest to people more familiar with RTL
> > >expansion -- generally I thought the callers of expand() have to deal
> > >with expansions that return a different mode?
> > You generally have to deal with expansions that return the object in a new
> > pseudo instead of the one you asked for -- so the caller has to test for
> > that and emit a copy when it happens.
> > 
> > I don't offhand recall cases where we have to deal with getting a result in
> > a different mode than was asked.  But given the history of the expanders, I
> > wouldn't be surprised if there's oddball cases where that can happen.
> 
> I've already committed the original patch based on Eric's review, but
> managed to come up with another testcase that still ICEs (one with two
> different complex modes).  Is the following ok for trunk if it passes
> bootstrap/regtest?

As we're dealing with memory isn't GET_MODE_SIZE the correct thing to
use?

> 2016-10-28  Jakub Jelinek  <ja...@redhat.com>
> 
>       PR rtl-optimization/77919
>       * expr.c (expand_expr_real_1) <normal_inner_ref>: Only avoid forcing
>       into memory if both modes are complex and their inner modes have the
>       same precision.  If the two modes are different complex modes, convert
>       each part separately and generate a new CONCAT.
> 
>       * g++.dg/torture/pr77919-2.C: New test.
> 
> --- gcc/expr.c.jj     2016-10-28 10:35:14.753234774 +0200
> +++ gcc/expr.c        2016-10-28 10:35:28.760057716 +0200
> @@ -10422,10 +10422,35 @@ expand_expr_real_1 (tree exp, rtx target
>         {
>           if (bitpos == 0
>               && bitsize == GET_MODE_BITSIZE (GET_MODE (op0))
> -             && COMPLEX_MODE_P (mode1))
> +             && COMPLEX_MODE_P (mode1)
> +             && COMPLEX_MODE_P (GET_MODE (op0))
> +             && (GET_MODE_PRECISION (GET_MODE_INNER (mode1))
> +                 == GET_MODE_PRECISION (GET_MODE_INNER (GET_MODE (op0)))))
>             {
>               if (reversep)
>                 op0 = flip_storage_order (GET_MODE (op0), op0);
> +             if (mode1 != GET_MODE (op0))
> +               {
> +                 rtx parts[2];
> +                 for (int i = 0; i < 2; i++)
> +                   {
> +                     rtx op = read_complex_part (op0, i != 0);
> +                     if (GET_CODE (op) == SUBREG)
> +                       op = force_reg (GET_MODE (op), op);
> +                     rtx temp = gen_lowpart_common (GET_MODE_INNER (mode1),
> +                                                    op);
> +                     if (temp)
> +                       op = temp;
> +                     else
> +                       {
> +                         if (!REG_P (op) && !MEM_P (op))
> +                           op = force_reg (GET_MODE (op), op);
> +                         op = gen_lowpart (GET_MODE_INNER (mode1), op);
> +                       }
> +                     parts[i] = op;
> +                   }
> +                 op0 = gen_rtx_CONCAT (mode1, parts[0], parts[1]);
> +               }
>               return op0;
>             }
>           if (bitpos == 0
> --- gcc/testsuite/g++.dg/torture/pr77919-2.C.jj       2016-10-28 
> 10:35:49.294798140 +0200
> +++ gcc/testsuite/g++.dg/torture/pr77919-2.C  2016-10-28 10:29:38.000000000 
> +0200
> @@ -0,0 +1,10 @@
> +// PR rtl-optimization/77919
> +// { dg-do compile }
> +
> +typedef _Complex long long B;
> +struct A { A (double) {} _Complex double i; };
> +typedef struct { B b; } C;
> +struct D { D (const B &x) : b (x) {} B b; };
> +static inline B foo (const double *x) { C *a; a = (C *) x; return a->b; }
> +static inline D baz (const A &x) { return foo ((double *) &x); }
> +D b = baz (0);
> 
> 
>       Jakub
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 
21284 (AG Nuernberg)

Reply via email to