expand_constructor passed int_expr_size to store_constructor, which is
-1 for a type whose size is a POLY_INT_CST.  The RECORD_TYPE case then
skipped clear_storage, so an empty CONSTRUCTOR of an SVE or RVV tuple
type stored nothing: a register target got only a clobber and a memory
target was left unchanged.  Pass the poly size instead; only types with
a POLY_INT_CST size are affected.

store_constructor now asserts that SIZE is nonnegative, so an unknown
size from any caller ICEs instead of leaving the object uninitialized.

Bootstrapped and regression tested on x86_64-pc-linux-gnu, including Ada.  On
aarch64-linux-gnu (qemu), regression tested dg.exp, aarch64.exp and
the SVE tests at SVE VL128, and the SVE tests at VL2048.  On
riscv64, compiling gcc.target/riscv/rvv/base changes the asm of the new
test only.

Assisted-by: Claude Opus 5 (Anthropic)

        PR middle-end/121105

gcc/ChangeLog:

        * expr.cc (store_constructor): Assert that SIZE is nonnegative.
        Drop the then-redundant known_size_p check.
        (expand_constructor): Pass the poly_int64 size of the type to
        store_constructor.

gcc/testsuite/ChangeLog:

        * gcc.target/aarch64/sve/pr121105_1.c: New test.
        * gcc.target/aarch64/sve/pr121105_2.c: New test.
        * g++.target/aarch64/sve/pr121105.C: New test.
        * gcc.target/riscv/rvv/base/pr121105.c: New test.

Signed-off-by: Dominic P <[email protected]>
---
v2: as Jeff Law suggested, store_constructor now asserts on entry that
SIZE is nonnegative, which covers all of its callers, and drops the
known_size_p test that the assert makes redundant.  expand_constructor
uses tree_to_poly_int64 instead of falling back to -1.  The gimplifier
lowers variable-sized CONSTRUCTORs (element stores, or memset when
empty), so no valid caller trips the assert.  Patch 1/2 is unchanged.

OK for trunk?

 gcc/expr.cc                                   |   9 +-
 .../g++.target/aarch64/sve/pr121105.C         |  13 ++
 .../gcc.target/aarch64/sve/pr121105_1.c       | 121 ++++++++++++++++++
 .../gcc.target/aarch64/sve/pr121105_2.c       |  33 +++++
 .../gcc.target/riscv/rvv/base/pr121105.c      |  21 +++
 5 files changed, 193 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.target/aarch64/sve/pr121105.C
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/pr121105_1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/pr121105_2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/pr121105.c

diff --git a/gcc/expr.cc b/gcc/expr.cc
index 94e3281b796..046b599cce7 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -7543,6 +7543,7 @@ store_constructor (tree exp, rtx target, int cleared, 
poly_int64 size,
 {
   tree type = TREE_TYPE (exp);
   HOST_WIDE_INT exp_size = int_size_in_bytes (type);
+  gcc_assert (known_ge (size, 0));
   poly_int64 bitregion_end = known_gt (size, 0) ? size * BITS_PER_UNIT - 1 : 0;
 
   switch (TREE_CODE (type))
@@ -7587,9 +7588,8 @@ store_constructor (tree exp, rtx target, int cleared, 
poly_int64 size,
           the whole structure first.  Don't do this if TARGET is a
           register whose mode size isn't equal to SIZE since
           clear_storage can't handle this case.  */
-       else if (known_size_p (size)
-                && (((int) CONSTRUCTOR_NELTS (exp) != fields_length (type))
-                    || mostly_zeros_p (exp))
+       else if ((((int) CONSTRUCTOR_NELTS (exp) != fields_length (type))
+                 || mostly_zeros_p (exp))
                 && (!REG_P (target)
                     || known_eq (GET_MODE_SIZE (GET_MODE (target)), size)))
          {
@@ -9573,7 +9573,8 @@ expand_constructor (tree exp, rtx target, enum 
expand_modifier modifier,
       target = assign_temp (type, TREE_ADDRESSABLE (exp), 1);
     }
 
-  store_constructor (exp, target, 0, int_expr_size (exp), false);
+  store_constructor (exp, target, 0, tree_to_poly_int64 (size_in_bytes (type)),
+                    false);
   return target;
 }
 
diff --git a/gcc/testsuite/g++.target/aarch64/sve/pr121105.C 
b/gcc/testsuite/g++.target/aarch64/sve/pr121105.C
new file mode 100644
index 00000000000..06aacb6c10a
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/sve/pr121105.C
@@ -0,0 +1,13 @@
+// PR middle-end/121105
+// { dg-do compile }
+// { dg-options "-O2" }
+
+#include <arm_sve.h>
+
+svfloat32x4_t
+e ()
+{
+  return svfloat32x4_t{};
+}
+
+// { dg-final { scan-assembler-times {\tmovi\td[0-3], #0\n} 4 } }
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pr121105_1.c 
b/gcc/testsuite/gcc.target/aarch64/sve/pr121105_1.c
new file mode 100644
index 00000000000..f508a35f526
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/pr121105_1.c
@@ -0,0 +1,121 @@
+/* PR middle-end/121105 */
+/* { dg-do run { target aarch64_sve_hw } } */
+/* { dg-options "-O2" } */
+
+#include <arm_sve.h>
+
+static int
+nonzero (svuint8_t v)
+{
+  return svptest_any (svptrue_b8 (), svcmpne (svptrue_b8 (), v, 0));
+}
+
+__attribute__((noipa)) svfloat32x4_t
+dirty4 (void)
+{
+  svfloat32_t v = svdup_f32 (-1.0f);
+  return svcreate4 (v, v, v, v);
+}
+
+__attribute__((noipa)) svfloat32x4_t
+ret4 (void)
+{
+  svfloat32x4_t x = {};
+  return x;
+}
+
+__attribute__((noipa)) svint8x2_t
+ret2 (void)
+{
+  return (svint8x2_t) {};
+}
+
+__attribute__((noipa)) void
+mem3 (svuint64x3_t *p)
+{
+  *p = (svuint64x3_t) {};
+}
+
+__attribute__((noipa)) void
+dirty_stack (void)
+{
+  volatile unsigned char buf[4096];
+  for (int i = 0; i < 4096; i++)
+    buf[i] = 0xff;
+}
+
+__attribute__((noipa)) int
+check2 (svint16x2_t *p)
+{
+  return (nonzero (svreinterpret_u8 (svget2 (*p, 0)))
+         || nonzero (svreinterpret_u8 (svget2 (*p, 1))));
+}
+
+__attribute__((noipa)) int
+addr2 (void)
+{
+  svint16x2_t x = {};
+  return check2 (&x);
+}
+
+__attribute__((noipa)) svboolx4_t
+dirtyb (void)
+{
+  svbool_t t = svptrue_b8 ();
+  return svcreate4 (t, t, t, t);
+}
+
+__attribute__((noipa)) svboolx4_t
+retb4 (void)
+{
+  return (svboolx4_t) {};
+}
+
+__attribute__((noipa)) void
+memb2 (svboolx2_t *p)
+{
+  *p = (svboolx2_t) {};
+}
+
+int
+main (void)
+{
+  dirty4 ();
+  svfloat32x4_t a = ret4 ();
+  if (nonzero (svreinterpret_u8 (svget4 (a, 0)))
+      || nonzero (svreinterpret_u8 (svget4 (a, 1)))
+      || nonzero (svreinterpret_u8 (svget4 (a, 2)))
+      || nonzero (svreinterpret_u8 (svget4 (a, 3))))
+    __builtin_abort ();
+
+  dirty4 ();
+  svint8x2_t b = ret2 ();
+  if (nonzero (svreinterpret_u8 (svget2 (b, 0)))
+      || nonzero (svreinterpret_u8 (svget2 (b, 1))))
+    __builtin_abort ();
+
+  svuint64_t m1 = svdup_u64 (-1);
+  svuint64x3_t c = svcreate3 (m1, m1, m1);
+  mem3 (&c);
+  if (nonzero (svreinterpret_u8 (svget3 (c, 0)))
+      || nonzero (svreinterpret_u8 (svget3 (c, 1)))
+      || nonzero (svreinterpret_u8 (svget3 (c, 2))))
+    __builtin_abort ();
+
+  dirty_stack ();
+  if (addr2 ())
+    __builtin_abort ();
+
+  svbool_t all = svptrue_b8 ();
+  dirtyb ();
+  svboolx4_t d = retb4 ();
+  if (svptest_any (all, svget4 (d, 0)) || svptest_any (all, svget4 (d, 1))
+      || svptest_any (all, svget4 (d, 2)) || svptest_any (all, svget4 (d, 3)))
+    __builtin_abort ();
+
+  svboolx2_t e = svcreate2 (all, all);
+  memb2 (&e);
+  if (svptest_any (all, svget2 (e, 0)) || svptest_any (all, svget2 (e, 1)))
+    __builtin_abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pr121105_2.c 
b/gcc/testsuite/gcc.target/aarch64/sve/pr121105_2.c
new file mode 100644
index 00000000000..1c50e31422f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/pr121105_2.c
@@ -0,0 +1,33 @@
+/* PR middle-end/121105 */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+#include <arm_sve.h>
+
+svboolx2_t
+ret2 (void)
+{
+  svboolx2_t x = {};
+  return x;
+}
+
+svboolx4_t
+ret4 (void)
+{
+  return (svboolx4_t) {};
+}
+
+void
+mem2 (svboolx2_t *p)
+{
+  *p = (svboolx2_t) {};
+}
+
+void
+mem4 (svboolx4_t *p)
+{
+  *p = (svboolx4_t) {};
+}
+
+/* { dg-final { scan-assembler-times {\tpfalse\tp[0-9]+\.b\n} 12 } } */
+/* { dg-final { scan-assembler-times {\tstr\tp[0-9]+, \[x0(?:, #[1-3], mul 
vl)?\]\n} 6 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr121105.c 
b/gcc/testsuite/gcc.target/riscv/rvv/base/pr121105.c
new file mode 100644
index 00000000000..118d4f04ed3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr121105.c
@@ -0,0 +1,21 @@
+/* PR middle-end/121105 */
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -O2" } */
+
+#include "riscv_vector.h"
+
+vint32m1x4_t
+ret4 (void)
+{
+  vint32m1x4_t x = {};
+  return x;
+}
+
+void
+mem2 (vint8m1x2_t *p)
+{
+  *p = (vint8m1x2_t) {};
+}
+
+/* { dg-final { scan-assembler-times 
{(?:vmv\.v\.i|vmv1r\.v)\s+v(?:8|9|10|11),} 4 } } */
+/* { dg-final { scan-assembler-times {vs1r\.v|vse8\.v} 2 } } */
-- 
2.56.0

Reply via email to