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);
     }
 
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" } */
+
+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);
+}
+}
-- 
2.55.0

Reply via email to