When COMPARE_MAX_PIECES is UNITS_PER_WORD (no SSE2, or SSE2 tunings
without fast unaligned SSE loads/stores such as core2), every word piece
gets its own compare and branch, so memcmp is only inlined up to 32
bytes for 64-bit and 16 bytes for ia32.

Use a branch ratio of 2 for word_mode pieces and halve SIZE in the cost
estimate when optimizing for speed, so the thresholds match the SSE2
ones: 64 bytes for 64-bit, 32 bytes for ia32.  Each pair of word pieces
is then compared with a sequence similar to the SSE2 double-word compare:
two loads, two subs, one or and one branch.

Bootstrapped and regtested on x86_64-pc-linux-gnu{-m32,}.
Ok for trunk?

gcc/ChangeLog:

        PR target/128035
        * config/i386/i386.cc (ix86_use_by_pieces_infrastructure_p): Halve
        SIZE for COMPARE_BY_PIECES when COMPARE_MAX_PIECES is
        UNITS_PER_WORD and optimizing for speed.
        (ix86_compare_by_pieces_branch_ratio): New function.
        (TARGET_COMPARE_BY_PIECES_BRANCH_RATIO): Define.

gcc/testsuite/ChangeLog:

        PR target/128035
        * gcc.target/i386/pr128035.c: New test.
---
 gcc/config/i386/i386.cc                  | 25 ++++++++++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr128035.c | 16 +++++++++++++++
 2 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr128035.c

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 136c339c8ca..1db8083dbc5 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -11637,9 +11637,30 @@ ix86_use_by_pieces_infrastructure_p (unsigned 
HOST_WIDE_INT size,
   if (cfun->machine->by_pieces_in_use)
     return true;
 
+  /* compare_by_pieces pairs up word-sized pieces before branching (see
+     ix86_compare_by_pieces_branch_ratio), which is the code a double-word
+     compare expands to.  Halve SIZE so the word-mode estimate gives the
+     same cutoff as the double-word path.  */
+  if (op == COMPARE_BY_PIECES
+      && COMPARE_MAX_PIECES == UNITS_PER_WORD
+      && speed_p)
+    size = CEIL (size, 2);
+
   return default_use_by_pieces_infrastructure_p (size, align, op,
                                                 speed_p);
 }
+
+/* Implement TARGET_COMPARE_BY_PIECES_BRANCH_RATIO.  */
+
+static int
+ix86_compare_by_pieces_branch_ratio (machine_mode mode)
+{
+  if (mode == word_mode
+      && COMPARE_MAX_PIECES == UNITS_PER_WORD
+      && optimize_insn_for_speed_p ())
+    return 2;
+  return 1;
+}
 
 /* Allow {LABEL | SYMBOL}_REF - SYMBOL_REF-FOR-PICBASE for Mach-O as
    this is used for to form addresses to local data when -fPIC is in
@@ -28984,6 +29005,10 @@ static const scoped_attribute_specs *const 
ix86_attribute_table[] =
 #define TARGET_USE_BY_PIECES_INFRASTRUCTURE_P \
   ix86_use_by_pieces_infrastructure_p
 
+#undef TARGET_COMPARE_BY_PIECES_BRANCH_RATIO
+#define TARGET_COMPARE_BY_PIECES_BRANCH_RATIO \
+  ix86_compare_by_pieces_branch_ratio
+
 #undef TARGET_OVERLAP_OP_BY_PIECES_P
 #define TARGET_OVERLAP_OP_BY_PIECES_P hook_bool_void_true
 
diff --git a/gcc/testsuite/gcc.target/i386/pr128035.c 
b/gcc/testsuite/gcc.target/i386/pr128035.c
new file mode 100644
index 00000000000..84a7c4486e6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr128035.c
@@ -0,0 +1,16 @@
+/* PR target/128035 */
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -mno-sse" } */
+/* { dg-final { scan-assembler-not "memcmp" } } */
+
+#define BUFSIZE 40
+
+struct foo {
+  char buf[BUFSIZE];
+};
+
+int
+test (struct foo *p1, struct foo *p2)
+{
+  return __builtin_memcmp (p1, p2, sizeof (struct foo)) == 0;
+}
-- 
2.34.1

Reply via email to