[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v9 2/5] x86/asm, x86/boot: expose inline memcmp()



On September 9, 2026 2:39:51 PM PDT, David Laight 
<david.laight.linux@xxxxxxxxx> wrote:
>On Wed, 09 Sep 2026 12:33:40 -0700
>"H. Peter Anvin" <hpa@xxxxxxxxx> wrote:
>
>> On September 9, 2026 12:28:38 PM PDT, David Laight 
>> <david.laight.linux@xxxxxxxxx> wrote:
>> >On Wed, 9 Sep 2026 06:43:01 -0700
>> >"H. Peter Anvin" <hpa@xxxxxxxxx> wrote:
>> >  
>> >> On 2026-09-09 01:38, David Laight wrote:  
>> >> >>
>> >> >> Here is an out-of-line compact memcmp() which works for both 16/32 and 
>> >> >> 64 bits:
>> >> >>    
>> >> <broken code removed>
>> >>   
>> >> >>
>> >> >> On 64 bits it compiles to:
>> >> >>
>> >> >> 0000000000000000 <memcmp>:
>> >> >>    0:   48 89 d1                mov    %rdx,%rcx
>> >> >>    3:   31 d2                   xor    %edx,%edx
>> >> >>    5:   31 c0                   xor    %eax,%eax
>> >> >>    7:   f3 a6                   repz cmpsb (%rdi),(%rsi)
>> >> >>    9:   0f 97 c2                seta   %dl
>> >> >>    c:   0f 92 c0                setb   %al
>> >> >>    f:   29 d0                   sub    %edx,%eax    
>> >> > 
>> >> > That isn't the object code from the source ...
>> >> >     
>> >> And that's the ultimate hint that a cut and paste error had happened.
>> >> 
>> >> This was the actual source code.
>> >> 
>> >> int memcmp(const void *s1, const void *s2, size_t len)
>> >> {
>> >>     int lt, gt;
>> >> 
>> >>     /*
>> >>      * Note: for the benefit of 64-bit code, xDI and xSI are reversed
>> >>      * compared with what CMPSB uses; hence SETA and SETB are also 
>> >> reversed.
>> >>      *
>> >>      * The XOR statements set ZF = 1, CF = 0, which is required to handle
>> >>      * the case len == 0 correctly.
>> >>      */
>> >>     asm volatile("xor %[lt],%[lt] ; "
>> >>                  "xor %[gt],%[gt] ; "
>> >>                  "repe cmpsb ; "
>> >>                  "seta %b[lt] ; "
>> >>                  "setb %b[gt]"
>> >>                  : "+D" (s1), "+S" (s2), "+c" (len),
>> >>                    [lt] "=&q" (lt), [gt] "=&q" (gt)
>> >>                  : : "cc", "memory");
>> >>     return gt - lt;
>> >> }
>> >>   
>> >
>> >Try:
>> >
>> >int memcmp_2(const void *s1, const void *s2, unsigned long len)
>> >{
>> >    signed char lt, gt;
>> >
>> >    asm volatile("repe cmpsb ; "
>> >                 "seta %[lt] ; "
>> >                 "setb %[gt]"
>> >                 : "+D" (s1), "+S" (s2), "+c" (len),
>> >                   [lt] "=&q" (lt), [gt] "=&q" (gt)
>> >                 : : "cc", "memory");
>> >    return (signed char)(gt - lt);
>> >}
>> >
>> >https://www.godbolt.org/z/6hrxGxb18
>> >
>> >Saves the XORs - go away completely in the usual case of 'if 
>> >(memcpy(....))'.
>> >The 'mess' on the return statement moves the sign extend after the
>> >subtract.
>> >
>> >David  
>> 
>> The xors are explicitly in the asm to deal with the len = 0 case (this is 
>> for the out of line version!)
>> 
>> We need to enter with ZF = 1 CF = 0.
>
>And, of course, I knew that.
>They also zero the high 24bits of the registers.
>Given the setup cost of 'repe cmpsb' I suspect the xor just add code
>bytes.
>
>David
>
>

The XOR is cheaper than the sign extend; look at the object code.



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.