"Robin Dapp" <[email protected]> writes:
> Hi,
>
> In extract_integral_bit_field we can get an unsplittable target like
> (reg:V2DF) and we try to store word-sized parts into it.  After the
> regmode-natural-size changes, this will ICE.  This patch spills the
> target in such a case.
>
> Bootstrapped and regtested on x86, power10, and aarch64.
> Regtested on riscv64.
>
> Regards
>  Robin
>
>       PR middle-end/127323
>
> gcc/ChangeLog:
>
>       * expmed.cc (extract_integral_bit_field): Spill unsplittable
>       target.
>
> gcc/testsuite/ChangeLog:
>
>       * g++.target/riscv/rvv/autovec/pr127323.C: New test.
> ---
>  gcc/expmed.cc                                 | 20 ++++++++--
>  .../g++.target/riscv/rvv/autovec/pr127323.C   | 39 +++++++++++++++++++
>  2 files changed, 56 insertions(+), 3 deletions(-)
>  create mode 100644 gcc/testsuite/g++.target/riscv/rvv/autovec/pr127323.C
>
> diff --git a/gcc/expmed.cc b/gcc/expmed.cc
> index 13803c6bbd0..fe8184e5031 100644
> --- a/gcc/expmed.cc
> +++ b/gcc/expmed.cc
> @@ -1987,6 +1987,14 @@ extract_integral_bit_field (rtx op0, 
> opt_scalar_int_mode op0_mode,
>        if (target == 0 || !REG_P (target) || !valid_multiword_target_p 
> (target))
>       target = gen_reg_rtx (mode);
>  
> +      /* If TARGET is unsplittable, work on a stack slot and copy back at the
> +      end.  */
> +      rtx orig_target = target;
> +      if (maybe_lt ((unsigned) UNITS_PER_WORD,
> +        (poly_uint64) REGMODE_NATURAL_SIZE (GET_MODE (target))))
> +     target = assign_stack_temp (GET_MODE (target),
> +                                 GET_MODE_SIZE (GET_MODE (target)));
> +
>        /* In case we're about to clobber a base register or something
>        (see gcc.c-torture/execute/20040625-1.c).   */
>        if (reg_mentioned_p (target, op0))
> @@ -2049,13 +2057,19 @@ extract_integral_bit_field (rtx op0, 
> opt_scalar_int_mode op0_mode,
>                                   1, VOIDmode),
>                  const0_rtx);
>           }
> -       return target;
> +
> +       if (target != orig_target)
> +         emit_move_insn (orig_target, target);
> +       return orig_target;
>       }
>  
> +      if (target != orig_target)
> +     emit_move_insn (orig_target, target);
> +
>        /* Signed bit field: sign-extend with two arithmetic shifts.  */
> -      target = expand_shift (LSHIFT_EXPR, mode, target,
> +      orig_target = expand_shift (LSHIFT_EXPR, mode, orig_target,
>                            GET_MODE_BITSIZE (mode) - bitsize, NULL_RTX, 0);
> -      return expand_shift (RSHIFT_EXPR, mode, target,
> +      return expand_shift (RSHIFT_EXPR, mode, orig_target,
>                          GET_MODE_BITSIZE (mode) - bitsize, NULL_RTX, 0);
>      }
>  

Could we instead do something like:

diff --git a/gcc/expmed.cc b/gcc/expmed.cc
index 13803c6bbd0..c6494484251 100644
--- a/gcc/expmed.cc
+++ b/gcc/expmed.cc
@@ -2022,14 +2022,16 @@ extract_integral_bit_field (rtx op0, 
opt_scalar_int_mode op0_mode,
                                   (unsignedp ? 1 : -1), target_part,
                                   mode, word_mode, reverse, fallback_p, NULL);
 
-         gcc_assert (target_part);
          if (!result_part)
            {
              delete_insns_since (last);
              return NULL;
            }
 
-         if (result_part != target_part)
+         if (!target_part)
+           store_bit_field (target, BITS_PER_WORD, i * BITS_PER_WORD,
+                            0, 0, word_mode, result_part, false, i == 0);
+         else if (result_part != target_part)
            emit_move_insn (target_part, result_part);
        }
 
It fixes the ICE but I haven't tested beyond that.

> diff --git a/gcc/testsuite/g++.target/riscv/rvv/autovec/pr127323.C 
> b/gcc/testsuite/g++.target/riscv/rvv/autovec/pr127323.C
> new file mode 100644
> index 00000000000..3809d81b6fe
> --- /dev/null
> +++ b/gcc/testsuite/g++.target/riscv/rvv/autovec/pr127323.C
> @@ -0,0 +1,39 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O3 -mrvv-max-lmul=conv-dynamic -march=rv64gcv -mabi=lp64d 
> -mvector-strict-align" } */

For me the ICE only triggered with -mtune=generic-ooo, as in the PR.

Richard

> +
> +typedef double VECTOR[3];
> +enum { X, Y, Z };
> +struct Bicubic_Patch_Struct {
> +  VECTOR Control_Points[4][4];
> +  VECTOR Bounding_Sphere_Center;
> +  double Bounding_Sphere_Radius;
> +};
> +void Assign_Vector(VECTOR d, VECTOR s) {
> +  d[X] = s[X];
> +  d[Y] = s[Y];
> +  d[Z] = s[Z];
> +}
> +typedef struct Bicubic_Patch_Struct BICUBIC_PATCH;
> +namespace std {
> +void find_average(int vector_count, VECTOR *vectors, VECTOR, double *radius) 
> {
> +  int i;
> +  double r0, r1, yc, zc, y0;
> +  for (i = 0; i < vector_count; i++) {
> +    yc += vectors[i][Y];
> +    zc += vectors[i][Z];
> +  }
> +  y0 = yc - zc;
> +  r1 = y0;
> +  if (r1)
> +    *radius = r0;
> +}
> +void Precompute_Patch_Values(BICUBIC_PATCH *Shape) {
> +  int i, j;
> +  VECTOR Control_Points[6];
> +  for (i = 0; i < 4; i++)
> +    for (j = 0; j < 4; j++)
> +      Assign_Vector(Control_Points[4 * i + j], Shape->Control_Points[i][j]);
> +  find_average(6, Control_Points, Shape->Bounding_Sphere_Center,
> +               &Shape->Bounding_Sphere_Radius);
> +}
> +}

Reply via email to