On Mon, Mar 4, 2024 at 9:25 AM Jakub Jelinek <ja...@redhat.com> wrote:
>
> Hi!
>
> The Intel extended format has the various weird number categories,
> pseudo denormals, pseudo infinities, pseudo NaNs and unnormals.
> Those are not representable in the GCC real_value and so neither
> GIMPLE nor RTX VIEW_CONVERT_EXPR/SUBREG folding folds those into
> constants.
>
> As can be seen on the following testcase, because it isn't folded
> (since GCC 12, before that we were folding it) we can end up with
> a SUBREG of a CONST_VECTOR or similar constant, which isn't valid
> general_operand, so we ICE during vregs pass trying to recognize
> the move instruction.
> Initially I thought it is a middle-end bug, the movxf instruction
> has general_operand predicate, but the middle-end certainly never
> tests that predicate, seems moves are special optabs.
> And looking at other mov optabs, e.g. for vector modes the i386
> patterns use nonimmediate_operand predicate on the input, yet
> ix86_expand_vector_move deals with CONSTANT_P and SUBREG of CONSTANT_P
> arguments which if the predicate was checked couldn't ever make it through.
>
> The following patch handles this case similarly to the
> ix86_expand_vector_move's SUBREG of CONSTANT_P case, does it just for XFmode
> because I believe that is the only mode that needs it from the scalar ones,
> others should just be folded.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
>
> 2024-03-04  Jakub Jelinek  <ja...@redhat.com>
>
>         PR target/114184
>         * config/i386/i386-expand.cc (ix86_expand_move): If XFmode op1
>         is SUBREG of CONSTANT_P, force the SUBREG_REG into memory or
>         register.
>
>         * gcc.target/i386/pr114184.c: New test.

OK, with a question inline.

Thanks,
Uros.

>
> --- gcc/config/i386/i386-expand.cc.jj   2024-03-01 14:56:34.120925989 +0100
> +++ gcc/config/i386/i386-expand.cc      2024-03-03 18:41:08.278793046 +0100
> @@ -451,6 +451,20 @@ ix86_expand_move (machine_mode mode, rtx
>           && GET_MODE (SUBREG_REG (op1)) == DImode
>           && SUBREG_BYTE (op1) == 0)
>         op1 = gen_rtx_ZERO_EXTEND (TImode, SUBREG_REG (op1));
> +      /* As not all values in XFmode are representable in real_value,
> +        we might be called with unfoldable SUBREGs of constants.  */
> +      if (mode == XFmode
> +         && CONSTANT_P (SUBREG_REG (op1))
> +         && can_create_pseudo_p ())

We have quite some unguarded force_regs in ix86_expand_move. While it
doesn't hurt to have an extra safety net, is there a particular reason
for can_create_pseudo_p check in the added code?

> +       {
> +         machine_mode imode = GET_MODE (SUBREG_REG (op1));
> +         rtx r = force_const_mem (imode, SUBREG_REG (op1));
> +         if (r)
> +           r = validize_mem (r);
> +         else
> +           r = force_reg (imode, SUBREG_REG (op1));
> +         op1 = simplify_gen_subreg (mode, r, imode, SUBREG_BYTE (op1));
> +       }
>        break;
>      }
>
> --- gcc/testsuite/gcc.target/i386/pr114184.c.jj 2024-03-03 18:45:45.912964030 
> +0100
> +++ gcc/testsuite/gcc.target/i386/pr114184.c    2024-03-03 18:45:37.639078138 
> +0100
> @@ -0,0 +1,22 @@
> +/* PR target/114184 */
> +/* { dg-do compile } */
> +/* { dg-options "-Og -mavx2" } */
> +
> +typedef unsigned char V __attribute__((vector_size (32)));
> +typedef unsigned char W __attribute__((vector_size (16)));
> +
> +_Complex long double
> +foo (void)
> +{
> +  _Complex long double d;
> +  *(V *)&d = (V) { 149, 136, 89, 42, 38, 240, 196, 194 };
> +  return d;
> +}
> +
> +long double
> +bar (void)
> +{
> +  long double d;
> +  *(W *)&d = (W) { 149, 136, 89, 42, 38, 240, 196, 194 };
> +  return d;
> +}
>
>         Jakub
>

Reply via email to