--- gcc-3.3.4/gcc/doc/md.texi.orig 2003-07-19 11:15:08.000000000 -0400 +++ gcc-3.3.4/gcc/doc/md.texi 2004-07-30 12:28:05.000000000 -0400 @@ -2709,13 +2709,23 @@ @cindex @code{cmpstr@var{m}} instruction pattern @item @samp{cmpstr@var{m}} -Block compare instruction, with five operands. Operand 0 is the output; +String compare instruction, with five operands. Operand 0 is the output; it has mode @var{m}. The remaining four operands are like the operands of @samp{movstr@var{m}}. The two memory blocks specified are compared byte by byte in lexicographic order. The effect of the instruction is to store a value in operand 0 whose sign indicates the result of the comparison. +@cindex @code{cmpmem@var{m}} instruction pattern +@item @samp{cmpmem@var{m}} +Block compare instruction, with five operands like the operands +of @samp{cmpstr@var{m}}. The two memory blocks specified are compared +byte by byte in lexicographic order starting at the beginning of each +block. Unlike @samp{cmpstr@var{m}} the instruction can prefetch +any bytes in the two memory blocks. The effect of the instruction is +to store a value in operand 0 whose sign indicates the result of the +comparison. + @cindex @code{strlen@var{m}} instruction pattern @item @samp{strlen@var{m}} Compute the length of a string, with three operands. --- gcc-3.3.4/gcc/optabs.c.orig 2004-03-02 19:48:54.000000000 -0500 +++ gcc-3.3.4/gcc/optabs.c 2004-07-30 12:28:05.000000000 -0400 @@ -3416,6 +3416,40 @@ if (size == 0) abort (); +#ifdef HAVE_cmpmemqi + if (HAVE_cmpmemqi + && GET_CODE (size) == CONST_INT + && INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode))) + { + result_mode = insn_data[(int) CODE_FOR_cmpmemqi].operand[0].mode; + result = gen_reg_rtx (result_mode); + emit_insn (gen_cmpmemqi (result, x, y, size, opalign)); + } + else +#endif +#ifdef HAVE_cmpmemhi + if (HAVE_cmpmemhi + && GET_CODE (size) == CONST_INT + && INTVAL (size) < (1 << GET_MODE_BITSIZE (HImode))) + { + result_mode = insn_data[(int) CODE_FOR_cmpmemhi].operand[0].mode; + result = gen_reg_rtx (result_mode); + emit_insn (gen_cmpmemhi (result, x, y, size, opalign)); + } + else +#endif +#ifdef HAVE_cmpmemsi + if (HAVE_cmpmemsi) + { + result_mode = insn_data[(int) CODE_FOR_cmpmemsi].operand[0].mode; + result = gen_reg_rtx (result_mode); + size = protect_from_queue (size, 0); + emit_insn (gen_cmpmemsi (result, x, y, + convert_to_mode (SImode, size, 1), + opalign)); + } + else +#endif #ifdef HAVE_cmpstrqi if (HAVE_cmpstrqi && GET_CODE (size) == CONST_INT --- gcc-3.3.4/gcc/config/s390/s390-protos.h.orig 2004-07-30 12:28:04.000000000 -0400 +++ gcc-3.3.4/gcc/config/s390/s390-protos.h 2004-07-30 12:28:05.000000000 -0400 @@ -69,7 +69,7 @@ extern void s390_load_address PARAMS ((rtx, rtx)); extern void s390_expand_movstr PARAMS ((rtx, rtx, rtx)); extern void s390_expand_clrstr PARAMS ((rtx, rtx)); -extern void s390_expand_cmpstr PARAMS ((rtx, rtx, rtx, rtx)); +extern void s390_expand_cmpmem PARAMS ((rtx, rtx, rtx, rtx)); extern rtx s390_return_addr_rtx PARAMS ((int, rtx)); extern void s390_output_symbolic_const PARAMS ((FILE *, rtx)); --- gcc-3.3.4/gcc/config/s390/s390.md.orig 2004-07-30 12:28:04.000000000 -0400 +++ gcc-3.3.4/gcc/config/s390/s390.md 2004-07-30 12:28:05.000000000 -0400 @@ -1961,33 +1961,33 @@ (set_attr "length" "8")]) ; -; cmpstrM instruction pattern(s). +; cmpmemM instruction pattern(s). ; -(define_expand "cmpstrdi" +(define_expand "cmpmemdi" [(set (match_operand:DI 0 "register_operand" "") (compare:DI (match_operand:BLK 1 "memory_operand" "") (match_operand:BLK 2 "memory_operand" "") ) ) (use (match_operand:DI 3 "general_operand" "")) (use (match_operand:DI 4 "" ""))] "TARGET_64BIT" - "s390_expand_cmpstr (operands[0], operands[1], + "s390_expand_cmpmem (operands[0], operands[1], operands[2], operands[3]); DONE;") -(define_expand "cmpstrsi" +(define_expand "cmpmemsi" [(set (match_operand:SI 0 "register_operand" "") (compare:SI (match_operand:BLK 1 "memory_operand" "") (match_operand:BLK 2 "memory_operand" "") ) ) (use (match_operand:SI 3 "general_operand" "")) (use (match_operand:SI 4 "" ""))] "" - "s390_expand_cmpstr (operands[0], operands[1], + "s390_expand_cmpmem (operands[0], operands[1], operands[2], operands[3]); DONE;") ; Compare a block that is up to 256 bytes in length. ; The block length is taken as (operands[2] % 256) + 1. -(define_insn "cmpstr_short_64" +(define_insn "cmpmem_short_64" [(set (reg:CCS 33) (compare:CCS (match_operand:BLK 0 "memory_operand" "=Q,Q") (match_operand:BLK 1 "memory_operand" "Q,Q"))) @@ -2015,7 +2015,7 @@ (set_attr "atype" "*,agen") (set_attr "length" "*,14")]) -(define_insn "cmpstr_short_31" +(define_insn "cmpmem_short_31" [(set (reg:CCS 33) (compare:CCS (match_operand:BLK 0 "memory_operand" "=Q,Q") (match_operand:BLK 1 "memory_operand" "Q,Q"))) @@ -2045,7 +2045,7 @@ ; Compare a block of arbitrary length. -(define_insn "cmpstr_long_64" +(define_insn "cmpmem_long_64" [(clobber (match_operand:TI 0 "register_operand" "=d")) (clobber (match_operand:TI 1 "register_operand" "=d")) (set (reg:CCS 33) @@ -2059,7 +2059,7 @@ (set_attr "type" "vs") (set_attr "length" "8")]) -(define_insn "cmpstr_long_31" +(define_insn "cmpmem_long_31" [(clobber (match_operand:DI 0 "register_operand" "=d")) (clobber (match_operand:DI 1 "register_operand" "=d")) (set (reg:CCS 33) --- gcc-3.3.4/gcc/config/s390/s390.c.orig 2004-07-30 12:28:04.000000000 -0400 +++ gcc-3.3.4/gcc/config/s390/s390.c 2004-07-30 12:28:05.000000000 -0400 @@ -3047,16 +3047,16 @@ and return the result in TARGET. */ void -s390_expand_cmpstr (target, op0, op1, len) +s390_expand_cmpmem (target, op0, op1, len) rtx target; rtx op0; rtx op1; rtx len; { rtx (*gen_short) PARAMS ((rtx, rtx, rtx)) = - TARGET_64BIT ? gen_cmpstr_short_64 : gen_cmpstr_short_31; + TARGET_64BIT ? gen_cmpmem_short_64 : gen_cmpmem_short_31; rtx (*gen_long) PARAMS ((rtx, rtx, rtx, rtx)) = - TARGET_64BIT ? gen_cmpstr_long_64 : gen_cmpstr_long_31; + TARGET_64BIT ? gen_cmpmem_long_64 : gen_cmpmem_long_31; rtx (*gen_result) PARAMS ((rtx)) = GET_MODE (target) == DImode ? gen_cmpint_di : gen_cmpint_si; --- gcc-3.3.4/gcc/config/i370/i370.md.orig 2002-01-20 18:48:11.000000000 -0500 +++ gcc-3.3.4/gcc/config/i370/i370.md 2004-07-30 12:28:05.000000000 -0400 @@ -474,10 +474,10 @@ ) ; -; cmpstrsi instruction pattern(s). +; cmpmemsi instruction pattern(s). ; -(define_expand "cmpstrsi" +(define_expand "cmpmemsi" [(set (match_operand:SI 0 "general_operand" "") (compare (match_operand:BLK 1 "general_operand" "") (match_operand:BLK 2 "general_operand" ""))) @@ -545,7 +545,7 @@ emit_move_insn (gen_rtx_SUBREG (SImode, reg2, GET_MODE_SIZE (SImode)), len); /* Compare! */ - emit_insn (gen_cmpstrsi_1 (result, reg1, reg2)); + emit_insn (gen_cmpmemsi_1 (result, reg1, reg2)); } DONE; }") @@ -569,7 +569,7 @@ ; Compare a block that is larger than 255 bytes in length. -(define_insn "cmpstrsi_1" +(define_insn "cmpmemsi_1" [(set (match_operand:SI 0 "register_operand" "+d") (compare (mem:BLK (subreg:SI (match_operand:DI 1 "register_operand" "+d") 0)) --- gcc-3.3.4/gcc/builtins.c.orig 2004-01-11 14:13:03.000000000 -0500 +++ gcc-3.3.4/gcc/builtins.c 2004-07-30 12:28:05.000000000 -0400 @@ -2418,7 +2418,7 @@ return expand_expr (result, target, mode, EXPAND_NORMAL); } -#ifdef HAVE_cmpstrsi +#if defined HAVE_cmpmemsi || defined HAVE_cmpstrsi { rtx arg1_rtx, arg2_rtx, arg3_rtx; rtx result; @@ -2428,8 +2428,19 @@ = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; int arg2_align = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; - enum machine_mode insn_mode - = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode; + enum machine_mode insn_mode; + +#ifdef HAVE_cmpmemsi + if (HAVE_cmpmemsi) + insn_mode = insn_data[(int) CODE_FOR_cmpmemsi].operand[0].mode; + else +#endif +#ifdef HAVE_cmpstrsi + if (HAVE_cmpstrsi) + insn_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode; + else +#endif + return 0; /* If we don't have POINTER_TYPE, call the function. */ if (arg1_align == 0 || arg2_align == 0) @@ -2445,11 +2456,19 @@ arg1_rtx = get_memory_rtx (arg1); arg2_rtx = get_memory_rtx (arg2); arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); - if (!HAVE_cmpstrsi) - insn = NULL_RTX; +#ifdef HAVE_cmpmemsi + if (HAVE_cmpmemsi) + insn = gen_cmpmemsi (result, arg1_rtx, arg2_rtx, arg3_rtx, + GEN_INT (MIN (arg1_align, arg2_align))); else +#endif +#ifdef HAVE_cmpstrsi + if (HAVE_cmpstrsi) insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx, GEN_INT (MIN (arg1_align, arg2_align))); + else +#endif + abort (); if (insn) emit_insn (insn); --- gcc-3.3.4/gcc/testsuite/gcc.dg/20030711-1.c.orig 2004-07-30 12:28:05.000000000 -0400 +++ gcc-3.3.4/gcc/testsuite/gcc.dg/20030711-1.c 2004-07-30 12:28:05.000000000 -0400 @@ -0,0 +1,25 @@ +/* Test whether strncmp has not been "optimized" into memcmp + nor any code with memcmp semantics. */ +/* { dg-do run { target i?86-*-linux* x86_64-*-linux* ia64-*-linux* alpha*-*-linux* powerpc*-*-linux* s390*-*-linux* sparc*-*-linux* } } */ +/* { dg-options "-O2" } */ +#include +#include + +void __attribute__((noinline)) test (const char *p) +{ + if (__builtin_strncmp (p, "abcdefghijklmnopq", 17) == 0) + abort (); +} + +int main (void) +{ + char *p = mmap (NULL, 131072, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (p == MAP_FAILED) + return 0; + if (munmap (p + 65536, 65536) < 0) + return 0; + __builtin_memcpy (p + 65536 - 5, "abcd", 5); + test (p + 65536 - 5); + return 0; +}