commit b41f96465190751561f6909e858604ceab00595b
Author: H.J. Lu <[email protected]>
Date: Mon Oct 20 16:14:34 2025 +0800
x86-64: Inline memmove with overlapping unaligned loads and stores.
inlines memmove with overlapping unaligned and stores. For
void
foo (char *dest, char *src, size_t len)
{
if (len <= 1)
__builtin_memmove (dest, src, len);
}
it uses overlapping unaligned and stores to move 1 byte:
cmpl $1, %edx
jb .L1
movl %edx, %edx
movzbl (%rsi), %ecx
movzbl -1(%rsi,%rdx), %eax
movb %cl, (%rdi)
movb %al, -1(%rdi,%rdx)
ret
Don't call ix86_expand_n_overlapping_move_movmem when max size == 1 to
generate:
cmpl $1, %edx
jb .L1
movzbl (%rsi), %eax
movb %al, (%rdi)
ret
gcc/
PR target/125968
* config/i386/i386-expand.cc (ix86_expand_movmem): Don't call
ix86_expand_n_overlapping_move_movmem when max size == 1.
gcc/testsuite/
PR target/125968
* gcc.target/i386/builtin-memmove-16.c: New test.
* gcc.target/i386/builtin-memmove-17.c: Likewise.
* gcc.target/i386/builtin-memmove-18a.c: Likewise.
* gcc.target/i386/builtin-memmove-18b.c: Likewise.
--
H.J.
From 756d90affbea88cff3b1f4e34e90a2898286aa6b Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <[email protected]>
Date: Wed, 24 Jun 2026 18:48:42 +0800
Subject: [PATCH] x86-64: Don't use overlapping unaligned moves to move 1 byte
commit b41f96465190751561f6909e858604ceab00595b
Author: H.J. Lu <[email protected]>
Date: Mon Oct 20 16:14:34 2025 +0800
x86-64: Inline memmove with overlapping unaligned loads and stores.
inlines memmove with overlapping unaligned and stores. For
void
foo (char *dest, char *src, size_t len)
{
if (len <= 1)
__builtin_memmove (dest, src, len);
}
it uses overlapping unaligned and stores to move 1 byte:
cmpl $1, %edx
jb .L1
movl %edx, %edx
movzbl (%rsi), %ecx
movzbl -1(%rsi,%rdx), %eax
movb %cl, (%rdi)
movb %al, -1(%rdi,%rdx)
ret
Don't call ix86_expand_n_overlapping_move_movmem when max size == 1 to
generate:
cmpl $1, %edx
jb .L1
movzbl (%rsi), %eax
movb %al, (%rdi)
ret
gcc/
PR target/125968
* config/i386/i386-expand.cc (ix86_expand_movmem): Don't call
ix86_expand_n_overlapping_move_movmem when max size == 1.
gcc/testsuite/
PR target/125968
* gcc.target/i386/builtin-memmove-16.c: New test.
* gcc.target/i386/builtin-memmove-17.c: Likewise.
* gcc.target/i386/builtin-memmove-18a.c: Likewise.
* gcc.target/i386/builtin-memmove-18b.c: Likewise.
Signed-off-by: H.J. Lu <[email protected]>
---
gcc/config/i386/i386-expand.cc | 11 +++--
.../gcc.target/i386/builtin-memmove-16.c | 42 +++++++++++++++++++
.../gcc.target/i386/builtin-memmove-17.c | 31 ++++++++++++++
.../gcc.target/i386/builtin-memmove-18a.c | 28 +++++++++++++
.../gcc.target/i386/builtin-memmove-18b.c | 6 +++
5 files changed, 115 insertions(+), 3 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/i386/builtin-memmove-16.c
create mode 100644 gcc/testsuite/gcc.target/i386/builtin-memmove-17.c
create mode 100644 gcc/testsuite/gcc.target/i386/builtin-memmove-18a.c
create mode 100644 gcc/testsuite/gcc.target/i386/builtin-memmove-18b.c
diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
index 2303de120ab..69265c4e228 100644
--- a/gcc/config/i386/i386-expand.cc
+++ b/gcc/config/i386/i386-expand.cc
@@ -10630,7 +10630,12 @@ ix86_expand_set_or_movmem (rtx operands[], bool iscpymem, bool issetmem)
probable_max_size = INTVAL (probable_max_size_exp);
if (CONST_INT_P (expected_size_exp))
expected_size = INTVAL (expected_size_exp);
- }
+
+ /* NB: This assert may fail without the fixes for
+ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125977
+ */
+ gcc_assert (min_size != max_size);
+ }
/* Make sure we don't need to care about overflow later on. */
if (count > (HOST_WIDE_INT_1U << 30))
@@ -10759,9 +10764,9 @@ ix86_expand_set_or_movmem (rtx operands[], bool iscpymem, bool issetmem)
nullptr, count_mode, 1,
more_2x_vec_label);
- if (min_size == 0 || min_size <= 2 * move_max)
+ if (max_size != 1 && (min_size == 0 || min_size <= 2 * move_max))
{
- /* Size >= MOVE_MAX and size <= 2 * MOVE_MAX. */
+ /* Max size != 1, size >= MOVE_MAX and size <= 2 * MOVE_MAX. */
ix86_expand_n_overlapping_move_set_or_movmem (dst, src,
memset_vals_p,
destreg, srcreg,
diff --git a/gcc/testsuite/gcc.target/i386/builtin-memmove-16.c b/gcc/testsuite/gcc.target/i386/builtin-memmove-16.c
new file mode 100644
index 00000000000..29fd84391c1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/builtin-memmove-16.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mno-avx -msse2 -mtune=generic -minline-all-stringops" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */
+/* { dg-final { check-function-bodies "**" "" "" { target { lp64 } } {^\t?\.} } } */
+
+/*
+**gcc_memmove:
+**.LFB0:
+** .cfi_startproc
+** cmpq \$2, %rdx
+** jbe .L7
+**.L1:
+** ret
+** .p2align 4,,10
+** .p2align 3
+**.L7:
+** cmpl \$2, %edx
+** jnb .L8
+** cmpl \$1, %edx
+** jb .L1
+** movzbl \(%rsi\), %eax
+** movb %al, \(%rdi\)
+** ret
+** .p2align 4,,10
+** .p2align 3
+**.L8:
+** movl %edx, %edx
+** movzwl \(%rsi\), %ecx
+** movzwl -2\(%rsi,%rdx\), %eax
+** movw %cx, \(%rdi\)
+** movw %ax, -2\(%rdi,%rdx\)
+** ret
+** .cfi_endproc
+**...
+*/
+
+void
+gcc_memmove (void *a, void *b, __SIZE_TYPE__ n)
+{
+ if (n < 3)
+ __builtin_memmove (a, b, n);
+}
diff --git a/gcc/testsuite/gcc.target/i386/builtin-memmove-17.c b/gcc/testsuite/gcc.target/i386/builtin-memmove-17.c
new file mode 100644
index 00000000000..8d55c21b73d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/builtin-memmove-17.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mno-avx -msse2 -mtune=generic -minline-all-stringops" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */
+/* { dg-final { check-function-bodies "**" "" "" { target { lp64 } } {^\t?\.} } } */
+
+/*
+**gcc_memmove:
+**.LFB0:
+** .cfi_startproc
+** cmpq \$1, %rdx
+** jbe .L7
+**.L1:
+** ret
+** .p2align 4,,10
+** .p2align 3
+**.L7:
+** cmpl \$1, %edx
+** jb .L1
+** movzbl \(%rsi\), %eax
+** movb %al, \(%rdi\)
+** ret
+** .cfi_endproc
+**...
+*/
+
+void
+gcc_memmove (void *a, void *b, __SIZE_TYPE__ n)
+{
+ if (n < 2)
+ __builtin_memmove (a, b, n);
+}
diff --git a/gcc/testsuite/gcc.target/i386/builtin-memmove-18a.c b/gcc/testsuite/gcc.target/i386/builtin-memmove-18a.c
new file mode 100644
index 00000000000..0eb92027a92
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/builtin-memmove-18a.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mno-avx -msse2 -mtune=generic" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */
+/* { dg-final { check-function-bodies "**" "" "" { target { lp64 } } {^\t?\.} } } */
+
+/*
+**gcc_memmove:
+**.LFB0:
+** .cfi_startproc
+** cmpq \$1, %rdx
+** je .L4
+** ret
+** .p2align 4,,10
+** .p2align 3
+**.L4:
+** movzbl \(%rsi\), %eax
+** movb %al, \(%rdi\)
+** ret
+** .cfi_endproc
+**...
+*/
+
+void
+gcc_memmove (void *a, void *b, __SIZE_TYPE__ n)
+{
+ if (n >= 1 && n <= 1)
+ __builtin_memmove (a, b, n);
+}
diff --git a/gcc/testsuite/gcc.target/i386/builtin-memmove-18b.c b/gcc/testsuite/gcc.target/i386/builtin-memmove-18b.c
new file mode 100644
index 00000000000..0a20955fc90
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/builtin-memmove-18b.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -mno-avx -msse2 -mtune=generic" } */
+
+#include "builtin-memmove-18a.c"
+
+/* { dg-final { scan-assembler "call _?memmove" } } */
--
2.54.0