overhaul optimized i386 memset asm
authorRich Felker <dalias@aerifal.cx>
Thu, 26 Feb 2015 06:51:39 +0000 (01:51 -0500)
committerRich Felker <dalias@aerifal.cx>
Thu, 26 Feb 2015 06:51:39 +0000 (01:51 -0500)
on most cpu models, "rep stosl" has high overhead that makes it
undesirable for small memset sizes. the new code extends the
minimal-branch fast path for short memsets from size 15 up to size 62,
and shrink-wraps this code path. in addition, "rep stosl" is very
sensitive to misalignment. the cost varies with size and with cpu
model, but it has been observed performing 1.5 to 4 times slower when
the destination address is not aligned mod 16. the new code thus
ensures alignment mod 16, but also preserves any existing additional
alignment, in case there are cpu models where it is beneficial.

this version is based in part on changes to the x86_64 memset asm
proposed by Denys Vlasenko.

src/string/i386/memset.s

index 06ac923..d00422c 100644 (file)
@@ -1,47 +1,76 @@
 .global memset
 .type memset,@function
 memset:
-       mov 8(%esp),%al
-       push %edi
-       mov %al,%ah
-       mov %al,%dl
-       mov 16(%esp),%ecx
-       shl $16,%eax
-       mov 8(%esp),%edi
-       mov %dl,%al
-       mov %dl,%ah
-       cmp $16,%ecx
-       jb 1f
+       mov 12(%esp),%ecx
+       cmp $62,%ecx
+       ja 2f
 
-       mov %eax,-4(%edi,%ecx)
-       shr $2,%ecx
-       rep
-       stosl
-       mov 8(%esp),%eax
-       pop %edi
-       ret
-
-1:     test %ecx,%ecx
+       mov 8(%esp),%dl
+       mov 4(%esp),%eax
+       test %ecx,%ecx
        jz 1f
 
-       mov %al,(%edi)
-       mov %al,-1(%edi,%ecx)
+       mov %dl,%dh
+
+       mov %dl,(%eax)
+       mov %dl,-1(%eax,%ecx)
        cmp $2,%ecx
        jbe 1f
 
-       mov %al,1(%edi)
-       mov %al,-2(%edi,%ecx)
-       cmp $4,%ecx
+       mov %dx,1(%eax)
+       mov %dx,(-1-2)(%eax,%ecx)
+       cmp $6,%ecx
        jbe 1f
 
-       mov %eax,(%edi)
-       mov %eax,-4(%edi,%ecx)
-       cmp $8,%ecx
+       shl $16,%edx
+       mov 8(%esp),%dl
+       mov 8(%esp),%dh
+
+       mov %edx,(1+2)(%eax)
+       mov %edx,(-1-2-4)(%eax,%ecx)
+       cmp $14,%ecx
        jbe 1f
 
-       mov %eax,4(%edi)
-       mov %eax,-8(%edi,%ecx)
+       mov %edx,(1+2+4)(%eax)
+       mov %edx,(1+2+4+4)(%eax)
+       mov %edx,(-1-2-4-8)(%eax,%ecx)
+       mov %edx,(-1-2-4-4)(%eax,%ecx)
+       cmp $30,%ecx
+       jbe 1f
+
+       mov %edx,(1+2+4+8)(%eax)
+       mov %edx,(1+2+4+8+4)(%eax)
+       mov %edx,(1+2+4+8+8)(%eax)
+       mov %edx,(1+2+4+8+12)(%eax)
+       mov %edx,(-1-2-4-8-16)(%eax,%ecx)
+       mov %edx,(-1-2-4-8-12)(%eax,%ecx)
+       mov %edx,(-1-2-4-8-8)(%eax,%ecx)
+       mov %edx,(-1-2-4-8-4)(%eax,%ecx)
+
+1:     ret     
+
+2:     movzbl 8(%esp),%eax
+       mov %edi,12(%esp)
+       imul $0x1010101,%eax
+       mov 4(%esp),%edi
+       test $15,%edi
+       mov %eax,-4(%edi,%ecx)
+       jnz 2f
 
-1:     mov 8(%esp),%eax
-       pop %edi
+1:     shr $2, %ecx
+       rep
+       stosl
+       mov 4(%esp),%eax
+       mov 12(%esp),%edi
        ret
+       
+2:     xor %edx,%edx
+       sub %edi,%edx
+       and $15,%edx
+       mov %eax,(%edi)
+       mov %eax,4(%edi)
+       mov %eax,8(%edi)
+       mov %eax,12(%edi)
+       sub %edx,%ecx
+       add %edx,%edi
+       jmp 1b