[2/2] expr: Clear an empty constructor of a poly-sized type [PR121105]

Message ID 20261002195044.3166661-3-gcc@gcc.dp11.uk
State New
Headers
Series Zero empty constructors of SVE and RVV tuple types [PR121105] |

Commit Message

Dominic P Oct. 2, 2026, 7:50 p.m. UTC
  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.

Bootstrapped and regression tested on x86_64-pc-linux-gnu.  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.  Tested together with the previous patch and the PR123370
patch.

Assisted-by: Claude Opus 5 (Anthropic)

	PR middle-end/121105

gcc/ChangeLog:

	* expr.cc (expand_constructor): Pass a poly_int64 size 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 <gcc@gcc.dp11.uk>
---
 gcc/expr.cc                                   |   5 +-
 .../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, 192 insertions(+), 1 deletion(-)
 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
  

Comments

Jeff Law Oct. 8, 2026, 2:40 a.m. UTC | #1
On 10/2/26 1:50 PM, Dominic P wrote:
> 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.
>
> Bootstrapped and regression tested on x86_64-pc-linux-gnu.  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.  Tested together with the previous patch and the PR123370
> patch.
>
> Assisted-by: Claude Opus 5 (Anthropic)
>
> 	PR middle-end/121105
>
> gcc/ChangeLog:
>
> 	* expr.cc (expand_constructor): Pass a poly_int64 size 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 <gcc@gcc.dp11.uk>
> ---
>   gcc/expr.cc                                   |   5 +-
>   .../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, 192 insertions(+), 1 deletion(-)
>   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 a9157dc5d41..6f8255f2d9f 100644
> --- a/gcc/expr.cc
> +++ b/gcc/expr.cc
> @@ -9573,7 +9573,10 @@ 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);
> +  poly_int64 size;
> +  if (!poly_int_tree_p (size_in_bytes (type), &size))
> +    size = -1;
> +  store_constructor (exp, target, 0, size, false);
>     return target;
>   }
>   
>
I'd be tempted to assert a sensible size either before the call to 
store_constructor or in store_constructor itself for sanity's sake. I'd 
hate someone to have to dive back into another case of an uninitialized 
object sneaking through unexpectedly.

jeff
  

Patch

diff --git a/gcc/expr.cc b/gcc/expr.cc
index a9157dc5d41..6f8255f2d9f 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -9573,7 +9573,10 @@  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);
+  poly_int64 size;
+  if (!poly_int_tree_p (size_in_bytes (type), &size))
+    size = -1;
+  store_constructor (exp, target, 0, size, 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 } } */