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