https://gcc.gnu.org/g:a3727eb5e821d6a1916805029aeaed092e5e739d

commit r16-4237-ga3727eb5e821d6a1916805029aeaed092e5e739d
Author: H.J. Lu <[email protected]>
Date:   Sat Oct 4 07:02:20 2025 +0800

    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]>

Diff:
---
 gcc/config/i386/i386-expand.cc           | 25 ++++++++++++++++++++++---
 gcc/testsuite/gcc.target/i386/pr122150.c | 21 +++++++++++++++++++++
 2 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
index c6f42275a3e5..0115af4d359e 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 000000000000..973c34d180ee
--- /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;
+}

Reply via email to