https://gcc.gnu.org/g:209757c5407dee80404800eff67e9dffb3430505

commit r17-1952-g209757c5407dee80404800eff67e9dffb3430505
Author: H.J. Lu <[email protected]>
Date:   Wed Jun 24 18:48:42 2026 +0800

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

Diff:
---
 gcc/config/i386/i386-expand.cc                     | 11 ++++--
 gcc/testsuite/gcc.target/i386/builtin-memmove-16.c | 42 ++++++++++++++++++++++
 gcc/testsuite/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(-)

diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
index 2303de120abf..69265c4e2287 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 000000000000..29fd84391c18
--- /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 000000000000..8d55c21b73da
--- /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 000000000000..0eb92027a928
--- /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 000000000000..0a20955fc90c
--- /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" } } */

Reply via email to