https://gcc.gnu.org/g:d139f7421dea271737d9085424fad84210c43b5e
commit r17-5498-gd139f7421dea271737d9085424fad84210c43b5e Author: liuhongt <[email protected]> Date: Thu Oct 22 04:25:00 2026 -0700 i386: Increase COMPARE_BY_PIECES threshold for word-sized pieces [PR128035] 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. 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.target/i386/pr128035-2.c: New test. Diff: --- gcc/config/i386/i386.cc | 25 +++++++++++++++++++++++++ gcc/testsuite/gcc.target/i386/pr128035-2.c | 16 ++++++++++++++++ gcc/testsuite/gcc.target/i386/pr128035.c | 16 ++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index 0e2be0254525..fd664fae18e3 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -11642,9 +11642,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 = (size >> 1) + (size & 1); + 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 @@ -29211,6 +29232,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-2.c b/gcc/testsuite/gcc.target/i386/pr128035-2.c new file mode 100644 index 000000000000..ba6ee05d7816 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr128035-2.c @@ -0,0 +1,16 @@ +/* PR target/128035 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mno-sse -w" } */ +/* { dg-final { scan-assembler-times "call\[ \t\]+_?memcmp" 2 } } */ + +int +f (char *p1, char *p2) +{ + return __builtin_memcmp (p1, p2, -1) == 0; +} + +int +g (char *p1, char *p2) +{ + return __builtin_bcmp (p1, p2, -1) == 0; +} diff --git a/gcc/testsuite/gcc.target/i386/pr128035.c b/gcc/testsuite/gcc.target/i386/pr128035.c new file mode 100644 index 000000000000..84a7c4486e66 --- /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; +}
