diff mbox

RFA: Do not use cmpstrnsi to implement builtin memcmp

Message ID m3r54t1d21.fsf@redhat.com
State New
Headers show

Commit Message

Nick Clifton Aug. 10, 2011, 3:49 p.m. UTC
Hi Guys,

This is a resend of a previously submitted patch:

  http://gcc.gnu.org/ml/gcc-patches/2009-03/msg00363.html

This version of the patch has been adjusted to apply to today's sources,
but otherwise it remains the same.

The point of the patch is that the cmpstrnsi machine pattern should not
be used to implement the memcmp builtin function.  This is because a
string comparison will terminate if two zero bytes are read whereas a
memory comparison should continue.

Tested without regressions on i686-pc-linux-gnu and rx-elf toolchains.

OK to apply ?

Cheers
  Nick

gcc/ChangeLog
2011-08-17  Nick Clifton  <nickc@redhat.com>

	* builtins.c (expand_builtin_memcmp): Do not use cmpstrnsi pattern.
	* doc/md.texi (cmpstrn): Note that the comparison stops if both
	fetched bytes are zero.
	(cmpstr): Likewise.
	(cmpmem): Note that the comparison does not stop if both of the
	fetched bytes are zero.

Comments

Jeff Law Aug. 10, 2011, 5:53 p.m. UTC | #1
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 08/10/11 09:49, Nick Clifton wrote:
> Hi Guys,
> 
> This is a resend of a previously submitted patch:
> 
> http://gcc.gnu.org/ml/gcc-patches/2009-03/msg00363.html
> 
> This version of the patch has been adjusted to apply to today's
> sources, but otherwise it remains the same.
> 
> The point of the patch is that the cmpstrnsi machine pattern should
> not be used to implement the memcmp builtin function.  This is
> because a string comparison will terminate if two zero bytes are read
> whereas a memory comparison should continue.
> 
> Tested without regressions on i686-pc-linux-gnu and rx-elf
> toolchains.
> 
> OK to apply ?
> 
> Cheers Nick
> 
> gcc/ChangeLog 2011-08-17  Nick Clifton  <nickc@redhat.com>
> 
> * builtins.c (expand_builtin_memcmp): Do not use cmpstrnsi pattern. *
> doc/md.texi (cmpstrn): Note that the comparison stops if both fetched
> bytes are zero. (cmpstr): Likewise. (cmpmem): Note that the
> comparison does not stop if both of the fetched bytes are zero.
OK.  Kindof surprised this wasn't dealt with before.  This sounds soo
much like something I've fixed in the past...

Jeff

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJOQsWZAAoJEBRtltQi2kC7tK0H/1bCmSvyrnDU+pmPo1blJzNo
MGcfo5pHiWnmEDO96HfR0OikLDj63Gu/Fks+c6NuZ+8dFvYCAldIDIprb7+27soi
VIxnGDkXFDJnqOLl7Nri6TW6CWazEPjQtALIcK2a4D+D20ZPlqLao6MIZSzdGdlk
5+giDVZ2sed7XmJYH413R53uTin/TxVCMijYP6smmBydXkdTgjRntNiq/kNBsnEo
v050MH5A5Wiyg4m22FB1vnmL3S4i8Vhq/lZANy/tMzdyO6eyoY36RvBUmBJ9ShAN
QYXrllnqwpzlsAdou5L1TmeBRk0iI9xxn1NkqDkDHo2er5oZTAzqqit0bht0zEw=
=paRW
-----END PGP SIGNATURE-----
Nick Clifton Aug. 12, 2011, 4:33 p.m. UTC | #2
Hi Jeff,

>> The point of the patch is that the cmpstrnsi machine pattern should
>> not be used to implement the memcmp builtin function.  This is
>> because a string comparison will terminate if two zero bytes are read
>> whereas a memory comparison should continue.

> OK.  Kindof surprised this wasn't dealt with before.

Me too.  Especially since the x86 port has a cmpstrnsi pattern and no 
cmpmemsi pattern...

I have applied the patch to the mainline and 4.6 and 4.5 branches.

Cheers
   Nick
diff mbox

Patch

Index: gcc/doc/md.texi
===================================================================
--- gcc/doc/md.texi	(revision 177611)
+++ gcc/doc/md.texi	(working copy)
@@ -4680,8 +4680,9 @@ 
 string.  The instruction is not allowed to prefetch more than one byte
 at a time since either string may end in the first byte and reading past
 that may access an invalid page or segment and cause a fault.  The
-effect of the instruction is to store a value in operand 0 whose sign
-indicates the result of the comparison.
+comparison terminates early if the fetched bytes are different or if
+they are equal to zero.  The effect of the instruction is to store a
+value in operand 0 whose sign indicates the result of the comparison.
 
 @cindex @code{cmpstr@var{m}} instruction pattern
 @item @samp{cmpstr@var{m}}
@@ -4699,8 +4700,10 @@ 
 order starting at the beginning of each string.  The instruction is not allowed
 to prefetch more than one byte at a time since either string may end in the
 first byte and reading past that may access an invalid page or segment and
-cause a fault.  The effect of the instruction is to store a value in operand 0
-whose sign indicates the result of the comparison.
+cause a fault.  The comparison will terminate when the fetched bytes
+are different or if they are equal to zero.  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}}
@@ -4708,9 +4711,10 @@ 
 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.
+any bytes in the two memory blocks.  Also unlike @samp{cmpstr@var{m}}
+the comparison will not stop if both bytes are zero.  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}}
Index: gcc/builtins.c
===================================================================
--- gcc/builtins.c	(revision 177611)
+++ gcc/builtins.c	(working copy)
@@ -3634,9 +3634,9 @@ 
 }
 
 /* Expand expression EXP, which is a call to the memcmp built-in function.
-   Return NULL_RTX if we failed and the
-   caller should emit a normal call, otherwise try to get the result in
-   TARGET, if convenient (and in mode MODE, if that's convenient).  */
+   Return NULL_RTX if we failed and the caller should emit a normal call,
+   otherwise try to get the result in TARGET, if convenient (and in mode
+   MODE, if that's convenient).  */
 
 static rtx
 expand_builtin_memcmp (tree exp, ATTRIBUTE_UNUSED rtx target,
@@ -3648,7 +3648,10 @@ 
  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return NULL_RTX;
 
-#if defined HAVE_cmpmemsi || defined HAVE_cmpstrnsi
+  /* Note: The cmpstrnsi pattern, if it exists, is not suitable for
+     implementing memcmp because it will stop if it encounters two
+     zero bytes.  */
+#if defined HAVE_cmpmemsi
   {
     rtx arg1_rtx, arg2_rtx, arg3_rtx;
     rtx result;
@@ -3663,16 +3666,9 @@ 
       = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
     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_cmpstrnsi
-    if (HAVE_cmpstrnsi)
-      insn_mode = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
-    else
-#endif
       return NULL_RTX;
 
     /* If we don't have POINTER_TYPE, call the function.  */
@@ -3697,18 +3693,10 @@ 
 	set_mem_size (arg2_rtx, INTVAL (arg3_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_cmpstrnsi
-    if (HAVE_cmpstrnsi)
-      insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
-			    GEN_INT (MIN (arg1_align, arg2_align)));
-    else
-#endif
       gcc_unreachable ();
 
     if (insn)
@@ -3734,7 +3722,7 @@ 
     else
       return convert_to_mode (mode, result, 0);
   }
-#endif
+#endif /* HAVE_cmpmemsi.  */
 
   return NULL_RTX;
 }