Since OP size passed to setmem_epilogue_gen_val may be smaller than the
required vector size, duplicate it first before setting vector.

gcc/

PR target/122150
* config/i386/i386-expand.cc (setmem_epilogue_gen_val): Duplicate
OP if its size is smaller than MODE size.

gcc/testsuite/

PR target/122150
* gcc.target/i386/pr122150.c: New test.

OK for master?

Thanks.

-- 
H.J.
From 0c39f2664ac6fbf50ec45f07e54ed45160d61f5c Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <[email protected]>
Date: Sat, 4 Oct 2025 07:02:20 +0800
Subject: [PATCH] x86: Handle small OP size in setmem_epilogue_gen_val

Since OP size passed to setmem_epilogue_gen_val may be smaller than the
required vector size, duplicate it first before setting vector.

gcc/

	PR target/122150
	* config/i386/i386-expand.cc (setmem_epilogue_gen_val): Duplicate
	OP if its size is smaller than MODE size.

gcc/testsuite/

	PR target/122150
	* gcc.target/i386/pr122150.c: New test.

Signed-off-by: H.J. Lu <[email protected]>
---
 gcc/config/i386/i386-expand.cc           | 25 +++++++++++++++++++++---
 gcc/testsuite/gcc.target/i386/pr122150.c | 21 ++++++++++++++++++++
 2 files changed, 43 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr122150.c

diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
index 26e39081143..f5fc63240d5 100644
--- a/gcc/config/i386/i386-expand.cc
+++ b/gcc/config/i386/i386-expand.cc
@@ -8443,9 +8443,28 @@ setmem_epilogue_gen_val (void *op_p, void *prev_p, HOST_WIDE_INT,
 
       unsigned int op_size = GET_MODE_SIZE (op_mode);
       unsigned int size = GET_MODE_SIZE (mode);
-      unsigned int nunits = op_size / GET_MODE_SIZE (QImode);
-      machine_mode vec_mode
-	= mode_for_vector (QImode, nunits).require ();
+      unsigned int nunits;
+      machine_mode vec_mode;
+      if (op_size < size)
+	{
+	  /* If OP size is smaller than MODE size, duplicate it.  */
+	  nunits = size / GET_MODE_SIZE (QImode);
+	  vec_mode = mode_for_vector (QImode, nunits).require ();
+	  nunits = size / op_size;
+	  gcc_assert (SCALAR_INT_MODE_P (op_mode));
+	  machine_mode dup_mode
+	    = mode_for_vector (as_a <scalar_mode> (op_mode),
+			       nunits).require ();
+	  target = gen_reg_rtx (vec_mode);
+	  op = gen_vec_duplicate (dup_mode, op);
+	  rtx dup_op = gen_reg_rtx (dup_mode);
+	  emit_move_insn (dup_op, op);
+	  op = gen_rtx_SUBREG (vec_mode, dup_op, 0);
+	  emit_move_insn (target, op);
+	  return target;
+	}
+      nunits = op_size / GET_MODE_SIZE (QImode);
+      vec_mode = mode_for_vector (QImode, nunits).require ();
       target = gen_reg_rtx (vec_mode);
       op = gen_rtx_SUBREG (vec_mode, op, 0);
       emit_move_insn (target, op);
diff --git a/gcc/testsuite/gcc.target/i386/pr122150.c b/gcc/testsuite/gcc.target/i386/pr122150.c
new file mode 100644
index 00000000000..973c34d180e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr122150.c
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-options "-mstringop-strategy=unrolled_loop" } */
+
+char c[2841];
+
+__attribute__((noipa))
+void
+foo (void)
+{
+  __builtin_memset (&c, 1, 2841);
+}
+
+int
+main (void)
+{
+  foo ();
+  for (unsigned i = 0; i < sizeof (c); i++)
+    if (c[i] != 1)
+      __builtin_abort();
+  return 0;
+}
-- 
2.51.0

Reply via email to