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 <hjl.tools@gmail.com>
This commit is contained in:
H.J. Lu 2025-10-04 07:02:20 +08:00
parent eb5a29677e
commit a3727eb5e8
2 changed files with 43 additions and 3 deletions

View File

@ -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);

View File

@ -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;
}