[2/2] expr: Clear an empty constructor of a poly-sized type [PR121105]
Commit Message
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
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
@@ -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;
}
new file mode 100644
@@ -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 } }
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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 } } */
new file mode 100644
@@ -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 } } */