diff options
author | Alan Modra <amodra@gmail.com> | 2013-08-17 18:48:36 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2013-10-04 10:41:46 +0930 |
commit | 466b03933234017473c12dd1d92bda5e7fe49df7 (patch) | |
tree | b70778371ad8c8e5a1ab77dee110d8711618abfd /sysdeps/powerpc/powerpc64/power7/rawmemchr.S | |
parent | 3be87c77d24c4456ccca4034363b6d1814cd0c84 (diff) | |
download | glibc-466b03933234017473c12dd1d92bda5e7fe49df7.tar.gz glibc-466b03933234017473c12dd1d92bda5e7fe49df7.tar.xz glibc-466b03933234017473c12dd1d92bda5e7fe49df7.zip |
PowerPC LE memchr and memrchr
http://sourceware.org/ml/libc-alpha/2013-08/msg00105.html Like strnlen, memchr and memrchr had a number of defects fixed by this patch as well as adding little-endian support. The first one I noticed was that the entry to the main loop needlessly checked for "are we done yet?" when we know the size is large enough that we can't be done. The second defect I noticed was that the main loop count was wrong, which in turn meant that the small loop needed to handle an extra word. Thirdly, there is nothing to say that the string can't wrap around zero, except of course that we'd normally hit a segfault on trying to read from address zero. Fixing that simplified a number of places: - /* Are we done already? */ - addi r9,r8,8 - cmpld r9,r7 - bge L(null) becomes + cmpld r8,r7 + beqlr However, the exit gets an extra test because I test for being on the last word then if so whether the byte offset is less than the end. Overall, the change is a win. Lastly, memrchr used the wrong cache hint. * sysdeps/powerpc/powerpc64/power7/memchr.S: Replace rlwimi with insrdi. Make better use of reg selection to speed exit slightly. Schedule entry path a little better. Remove useless "are we done" checks on entry to main loop. Handle wrapping around zero address. Correct main loop count. Handle single left-over word from main loop inline rather than by using loop_small. Remove extra word case in loop_small caused by wrong loop count. Add little-endian support. * sysdeps/powerpc/powerpc32/power7/memchr.S: Likewise. * sysdeps/powerpc/powerpc64/power7/memrchr.S: Likewise. Use proper cache hint. * sysdeps/powerpc/powerpc32/power7/memrchr.S: Likewise. * sysdeps/powerpc/powerpc64/power7/rawmemchr.S: Add little-endian support. Avoid rlwimi. * sysdeps/powerpc/powerpc32/power7/rawmemchr.S: Likewise.
Diffstat (limited to 'sysdeps/powerpc/powerpc64/power7/rawmemchr.S')
-rw-r--r-- | sysdeps/powerpc/powerpc64/power7/rawmemchr.S | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/sysdeps/powerpc/powerpc64/power7/rawmemchr.S b/sysdeps/powerpc/powerpc64/power7/rawmemchr.S index 50a33d8fae..547aed771f 100644 --- a/sysdeps/powerpc/powerpc64/power7/rawmemchr.S +++ b/sysdeps/powerpc/powerpc64/power7/rawmemchr.S @@ -27,8 +27,8 @@ ENTRY (__rawmemchr) clrrdi r8,r3,3 /* Align the address to doubleword boundary. */ /* Replicate byte to doubleword. */ - rlwimi r4,r4,8,16,23 - rlwimi r4,r4,16,0,15 + insrdi r4,r4,8,48 + insrdi r4,r4,16,32 insrdi r4,r4,32,0 /* Now r4 has a doubleword of c bytes. */ @@ -36,8 +36,13 @@ ENTRY (__rawmemchr) rlwinm r6,r3,3,26,28 /* Calculate padding. */ ld r12,0(r8) /* Load doubleword from memory. */ cmpb r5,r12,r4 /* Compare each byte against c byte. */ +#ifdef __LITTLE_ENDIAN__ + srd r5,r5,r6 + sld r5,r5,r6 +#else sld r5,r5,r6 /* Move left to discard ignored bits. */ srd r5,r5,r6 /* Bring the bits back as zeros. */ +#endif cmpdi cr7,r5,0 /* If r5 == 0, no c bytes have been found. */ bne cr7,L(done) @@ -91,8 +96,14 @@ L(loop): doubleword from the string. Use that fact to find out what is the position of the byte inside the string. */ L(done): +#ifdef __LITTLE_ENDIAN__ + addi r0,r5,-1 + andc r0,r0,r5 + popcntd r0,r0 /* Count trailing zeros. */ +#else cntlzd r0,r5 /* Count leading zeros before the match. */ - srdi r0,r0,3 /* Convert leading zeroes to bytes. */ +#endif + srdi r0,r0,3 /* Convert leading zeros to bytes. */ add r3,r8,r0 /* Return address of the matching char. */ blr END (__rawmemchr) |