diff options
Diffstat (limited to 'packages/glibc/2.17/0051-glibc-ppc64le-29.patch')
-rw-r--r-- | packages/glibc/2.17/0051-glibc-ppc64le-29.patch | 642 |
1 files changed, 642 insertions, 0 deletions
diff --git a/packages/glibc/2.17/0051-glibc-ppc64le-29.patch b/packages/glibc/2.17/0051-glibc-ppc64le-29.patch new file mode 100644 index 0000000..291155e --- /dev/null +++ b/packages/glibc/2.17/0051-glibc-ppc64le-29.patch @@ -0,0 +1,642 @@ +# commit 664318c3eb07032e2bfcf47cb2aa3c89280c19e7 +# Author: Alan Modra <amodra@gmail.com> +# Date: Sat Aug 17 18:46:05 2013 +0930 +# +# PowerPC LE strchr +# http://sourceware.org/ml/libc-alpha/2013-08/msg00101.html +# +# Adds little-endian support to optimised strchr assembly. I've also +# tweaked the big-endian code a little. In power7/strchr.S there's a +# check in the tail of the function that we didn't match 0 before +# finding a c match, done by comparing leading zero counts. It's just +# as valid, and quicker, to compare the raw output from cmpb. +# +# Another little tweak is to use rldimi/insrdi in place of rlwimi for +# the power7 strchr functions. Since rlwimi is cracked, it is a few +# cycles slower. rldimi can be used on the 32-bit power7 functions +# too. +# +# * sysdeps/powerpc/powerpc64/power7/strchr.S (strchr): Add little-endian +# support. Correct typos, formatting. Optimize tail. Use insrdi +# rather than rlwimi. +# * sysdeps/powerpc/powerpc32/power7/strchr.S: Likewise. +# * sysdeps/powerpc/powerpc64/power7/strchrnul.S (__strchrnul): Add +# little-endian support. Correct typos. +# * sysdeps/powerpc/powerpc32/power7/strchrnul.S: Likewise. Use insrdi +# rather than rlwimi. +# * sysdeps/powerpc/powerpc64/strchr.S (rTMP4, rTMP5): Define. Use +# in loop and entry code to keep "and." results. +# (strchr): Add little-endian support. Comment. Move cntlzd +# earlier in tail. +# * sysdeps/powerpc/powerpc32/strchr.S: Likewise. +# +Index: glibc-2.17-c758a686/sysdeps/powerpc/powerpc32/power7/strchr.S +=================================================================== +--- glibc-2.17-c758a686/sysdeps/powerpc/powerpc32/power7/strchr.S.orig ++++ glibc-2.17-c758a686/sysdeps/powerpc/powerpc32/power7/strchr.S +@@ -37,8 +37,8 @@ ENTRY (BP_SYM(strchr)) + beq cr7,L(null_match) + + /* Replicate byte to word. */ +- rlwimi r4,r4,8,16,23 +- rlwimi r4,r4,16,0,15 ++ insrdi r4,r4,8,48 ++ insrdi r4,r4,16,32 + + /* Now r4 has a word of c bytes and r0 has + a word of null bytes. */ +@@ -48,11 +48,17 @@ ENTRY (BP_SYM(strchr)) + + /* Move the words left and right to discard the bits that are + not part of the string and to bring them back as zeros. */ +- ++#ifdef __LITTLE_ENDIAN__ ++ srw r10,r10,r6 ++ srw r11,r11,r6 ++ slw r10,r10,r6 ++ slw r11,r11,r6 ++#else + slw r10,r10,r6 + slw r11,r11,r6 + srw r10,r10,r6 + srw r11,r11,r6 ++#endif + or r5,r10,r11 /* OR the results to speed things up. */ + cmpwi cr7,r5,0 /* If r5 == 0, no c or null bytes + have been found. */ +@@ -67,7 +73,7 @@ ENTRY (BP_SYM(strchr)) + + /* Handle WORD2 of pair. */ + lwzu r12,4(r8) +- cmpb r10,r12,r4 ++ cmpb r10,r12,r4 + cmpb r11,r12,r0 + or r5,r10,r11 + cmpwi cr7,r5,0 +@@ -102,22 +108,31 @@ L(loop): + bne cr6,L(done) + + /* The c/null byte must be in the second word. Adjust the address +- again and move the result of cmpb to r10 so we can calculate the +- pointer. */ ++ again and move the result of cmpb to r10/r11 so we can calculate ++ the pointer. */ + + mr r10,r6 + mr r11,r7 + addi r8,r8,4 + +- /* r5 has the output of the cmpb instruction, that is, it contains ++ /* r10/r11 have the output of the cmpb instructions, that is, + 0xff in the same position as the c/null byte in the original + word from the string. Use that to calculate the pointer. */ + L(done): +- cntlzw r4,r10 /* Count leading zeroes before c matches. */ +- cntlzw r0,r11 /* Count leading zeroes before null matches. */ +- cmplw cr7,r4,r0 ++#ifdef __LITTLE_ENDIAN__ ++ addi r3,r10,-1 ++ andc r3,r3,r10 ++ popcntw r0,r3 ++ addi r4,r11,-1 ++ andc r4,r4,r11 ++ cmplw cr7,r3,r4 ++ bgt cr7,L(no_match) ++#else ++ cntlzw r0,r10 /* Count leading zeros before c matches. */ ++ cmplw cr7,r11,r10 + bgt cr7,L(no_match) +- srwi r0,r4,3 /* Convert leading zeroes to bytes. */ ++#endif ++ srwi r0,r0,3 /* Convert leading zeros to bytes. */ + add r3,r8,r0 /* Return address of the matching c byte + or null in case c was not found. */ + blr +@@ -135,10 +150,14 @@ L(null_match): + cmpb r5,r12,r0 /* Compare each byte against null bytes. */ + + /* Move the words left and right to discard the bits that are +- not part of the string and to bring them back as zeros. */ +- ++ not part of the string and bring them back as zeros. */ ++#ifdef __LITTLE_ENDIAN__ ++ srw r5,r5,r6 ++ slw r5,r5,r6 ++#else + slw r5,r5,r6 + srw r5,r5,r6 ++#endif + cmpwi cr7,r5,0 /* If r10 == 0, no c or null bytes + have been found. */ + bne cr7,L(done_null) +@@ -193,7 +212,13 @@ L(loop_null): + 0xff in the same position as the null byte in the original + word from the string. Use that to calculate the pointer. */ + L(done_null): ++#ifdef __LITTLE_ENDIAN__ ++ addi r0,r5,-1 ++ andc r0,r0,r5 ++ popcntw r0,r0 ++#else + cntlzw r0,r5 /* Count leading zeros before the match. */ ++#endif + srwi r0,r0,3 /* Convert leading zeros to bytes. */ + add r3,r8,r0 /* Return address of the matching null byte. */ + blr +Index: glibc-2.17-c758a686/sysdeps/powerpc/powerpc32/power7/strchrnul.S +=================================================================== +--- glibc-2.17-c758a686/sysdeps/powerpc/powerpc32/power7/strchrnul.S.orig ++++ glibc-2.17-c758a686/sysdeps/powerpc/powerpc32/power7/strchrnul.S +@@ -29,8 +29,8 @@ ENTRY (BP_SYM(__strchrnul)) + clrrwi r8,r3,2 /* Align the address to word boundary. */ + + /* Replicate byte to word. */ +- rlwimi r4,r4,8,16,23 +- rlwimi r4,r4,16,0,15 ++ insrdi r4,r4,8,48 ++ insrdi r4,r4,16,32 + + rlwinm r6,r3,3,27,28 /* Calculate padding. */ + lwz r12,0(r8) /* Load word from memory. */ +@@ -45,10 +45,17 @@ ENTRY (BP_SYM(__strchrnul)) + + /* Move the words left and right to discard the bits that are + not part of the string and bring them back as zeros. */ ++#ifdef __LITTLE_ENDIAN__ ++ srw r10,r10,r6 ++ srw r9,r9,r6 ++ slw r10,r10,r6 ++ slw r9,r9,r6 ++#else + slw r10,r10,r6 + slw r9,r9,r6 + srw r10,r10,r6 + srw r9,r9,r6 ++#endif + or r5,r9,r10 /* OR the results to speed things up. */ + cmpwi cr7,r5,0 /* If r5 == 0, no c or null bytes + have been found. */ +@@ -56,7 +63,7 @@ ENTRY (BP_SYM(__strchrnul)) + + mtcrf 0x01,r8 + +- /* Are we now aligned to a quadword boundary? If so, skip to ++ /* Are we now aligned to a doubleword boundary? If so, skip to + the main loop. Otherwise, go through the alignment code. */ + + bt 29,L(loop) +@@ -78,7 +85,7 @@ L(loop): + single register for speed. This is an attempt + to speed up the null-checking process for bigger strings. */ + lwz r12,4(r8) +- lwzu r11,8(r8) ++ lwzu r11,8(r8) + cmpb r10,r12,r0 + cmpb r9,r12,r4 + cmpb r6,r11,r0 +@@ -97,9 +104,9 @@ L(loop): + addi r8,r8,-4 + bne cr6,L(done) + +- /* The c/null byte must be in the second word. Adjust the +- address again and move the result of cmpb to r10 so we can calculate +- the pointer. */ ++ /* The c/null byte must be in the second word. Adjust the address ++ again and move the result of cmpb to r5 so we can calculate the ++ pointer. */ + mr r5,r10 + addi r8,r8,4 + +@@ -107,7 +114,13 @@ L(loop): + 0xff in the same position as the c/null byte in the original + word from the string. Use that to calculate the pointer. */ + L(done): ++#ifdef __LITTLE_ENDIAN__ ++ addi r0,r5,-1 ++ andc r0,r0,r5 ++ popcntw r0,r0 ++#else + cntlzw r0,r5 /* Count leading zeros before the match. */ ++#endif + srwi r0,r0,3 /* Convert leading zeros to bytes. */ + add r3,r8,r0 /* Return address of matching c/null byte. */ + blr +Index: glibc-2.17-c758a686/sysdeps/powerpc/powerpc32/strchr.S +=================================================================== +--- glibc-2.17-c758a686/sysdeps/powerpc/powerpc32/strchr.S.orig ++++ glibc-2.17-c758a686/sysdeps/powerpc/powerpc32/strchr.S +@@ -44,6 +44,8 @@ ENTRY (BP_SYM (strchr)) + #define rIGN r10 /* number of bits we should ignore in the first word */ + #define rMASK r11 /* mask with the bits to ignore set to 0 */ + #define rTMP3 r12 ++#define rTMP4 rIGN ++#define rTMP5 rMASK + + CHECK_BOUNDS_LOW (rSTR, rTMP1, rTMP2) + STORE_RETURN_BOUNDS (rTMP1, rTMP2) +@@ -59,53 +61,74 @@ ENTRY (BP_SYM (strchr)) + addi r7F7F, r7F7F, 0x7f7f + /* Test the first (partial?) word. */ + lwz rWORD, 0(rSTR) ++#ifdef __LITTLE_ENDIAN__ ++ slw rMASK, rMASK, rIGN ++#else + srw rMASK, rMASK, rIGN ++#endif + orc rWORD, rWORD, rMASK + add rTMP1, rFEFE, rWORD + nor rTMP2, r7F7F, rWORD +- and. rTMP1, rTMP1, rTMP2 ++ and. rTMP4, rTMP1, rTMP2 + xor rTMP3, rCHR, rWORD + orc rTMP3, rTMP3, rMASK + b L(loopentry) + + /* The loop. */ + +-L(loop):lwzu rWORD, 4(rSTR) +- and. rTMP1, rTMP1, rTMP2 ++L(loop): ++ lwzu rWORD, 4(rSTR) ++ and. rTMP5, rTMP1, rTMP2 + /* Test for 0. */ +- add rTMP1, rFEFE, rWORD +- nor rTMP2, r7F7F, rWORD ++ add rTMP1, rFEFE, rWORD /* x - 0x01010101. */ ++ nor rTMP2, r7F7F, rWORD /* ~(x | 0x7f7f7f7f) == ~x & 0x80808080. */ + bne L(foundit) +- and. rTMP1, rTMP1, rTMP2 ++ and. rTMP4, rTMP1, rTMP2 /* (x - 0x01010101) & ~x & 0x80808080. */ + /* Start test for the bytes we're looking for. */ + xor rTMP3, rCHR, rWORD + L(loopentry): + add rTMP1, rFEFE, rTMP3 + nor rTMP2, r7F7F, rTMP3 + beq L(loop) ++ + /* There is a zero byte in the word, but may also be a matching byte (either + before or after the zero byte). In fact, we may be looking for a +- zero byte, in which case we return a match. We guess that this hasn't +- happened, though. */ +-L(missed): +- and. rTMP1, rTMP1, rTMP2 ++ zero byte, in which case we return a match. */ ++ and. rTMP5, rTMP1, rTMP2 + li rRTN, 0 + STORE_RETURN_VALUE (rSTR) + beqlr +-/* It did happen. Decide which one was first... +- I'm not sure if this is actually faster than a sequence of +- rotates, compares, and branches (we use it anyway because it's shorter). */ ++/* At this point: ++ rTMP5 bytes are 0x80 for each match of c, 0 otherwise. ++ rTMP4 bytes are 0x80 for each match of 0, 0 otherwise. ++ But there may be false matches in the next most significant byte from ++ a true match due to carries. This means we need to recalculate the ++ matches using a longer method for big-endian. */ ++#ifdef __LITTLE_ENDIAN__ ++ addi rTMP1, rTMP5, -1 ++ andc rTMP1, rTMP1, rTMP5 ++ cntlzw rCLZB, rTMP1 ++ addi rTMP2, rTMP4, -1 ++ andc rTMP2, rTMP2, rTMP4 ++ cmplw rTMP1, rTMP2 ++ bgtlr ++ subfic rCLZB, rCLZB, 32-7 ++#else ++/* I think we could reduce this by two instructions by keeping the "nor" ++ results from the loop for reuse here. See strlen.S tail. Similarly ++ one instruction could be pruned from L(foundit). */ + and rFEFE, r7F7F, rWORD +- or rMASK, r7F7F, rWORD ++ or rTMP5, r7F7F, rWORD + and rTMP1, r7F7F, rTMP3 +- or rIGN, r7F7F, rTMP3 ++ or rTMP4, r7F7F, rTMP3 + add rFEFE, rFEFE, r7F7F + add rTMP1, rTMP1, r7F7F +- nor rWORD, rMASK, rFEFE +- nor rTMP2, rIGN, rTMP1 ++ nor rWORD, rTMP5, rFEFE ++ nor rTMP2, rTMP4, rTMP1 ++ cntlzw rCLZB, rTMP2 + cmplw rWORD, rTMP2 + bgtlr +- cntlzw rCLZB, rTMP2 ++#endif + srwi rCLZB, rCLZB, 3 + add rRTN, rSTR, rCLZB + CHECK_BOUNDS_HIGH_RTN (rSTR, rTMP2, twlge) +@@ -113,13 +136,21 @@ L(missed): + blr + + L(foundit): ++#ifdef __LITTLE_ENDIAN__ ++ addi rTMP1, rTMP5, -1 ++ andc rTMP1, rTMP1, rTMP5 ++ cntlzw rCLZB, rTMP1 ++ subfic rCLZB, rCLZB, 32-7-32 ++ srawi rCLZB, rCLZB, 3 ++#else + and rTMP1, r7F7F, rTMP3 +- or rIGN, r7F7F, rTMP3 ++ or rTMP4, r7F7F, rTMP3 + add rTMP1, rTMP1, r7F7F +- nor rTMP2, rIGN, rTMP1 ++ nor rTMP2, rTMP4, rTMP1 + cntlzw rCLZB, rTMP2 + subi rSTR, rSTR, 4 + srwi rCLZB, rCLZB, 3 ++#endif + add rRTN, rSTR, rCLZB + CHECK_BOUNDS_HIGH_RTN (rSTR, rTMP2, twlge) + STORE_RETURN_VALUE (rSTR) +Index: glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/power7/strchr.S +=================================================================== +--- glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/power7/strchr.S.orig ++++ glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/power7/strchr.S +@@ -37,8 +37,8 @@ ENTRY (BP_SYM(strchr)) + beq cr7,L(null_match) + + /* 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 and r0 has +@@ -49,11 +49,17 @@ ENTRY (BP_SYM(strchr)) + + /* Move the doublewords left and right to discard the bits that are + not part of the string and bring them back as zeros. */ +- ++#ifdef __LITTLE_ENDIAN__ ++ srd r10,r10,r6 ++ srd r11,r11,r6 ++ sld r10,r10,r6 ++ sld r11,r11,r6 ++#else + sld r10,r10,r6 + sld r11,r11,r6 + srd r10,r10,r6 + srd r11,r11,r6 ++#endif + or r5,r10,r11 /* OR the results to speed things up. */ + cmpdi cr7,r5,0 /* If r5 == 0, no c or null bytes + have been found. */ +@@ -110,15 +116,24 @@ L(loop): + mr r11,r7 + addi r8,r8,8 + +- /* r5 has the output of the cmpb instruction, that is, it contains ++ /* r10/r11 have the output of the cmpb instructions, that is, + 0xff in the same position as the c/null byte in the original + doubleword from the string. Use that to calculate the pointer. */ + L(done): +- cntlzd r4,r10 /* Count leading zeroes before c matches. */ +- cntlzd r0,r11 /* Count leading zeroes before null matches. */ +- cmpld cr7,r4,r0 ++#ifdef __LITTLE_ENDIAN__ ++ addi r3,r10,-1 ++ andc r3,r3,r10 ++ popcntd r0,r3 ++ addi r4,r11,-1 ++ andc r4,r4,r11 ++ cmpld cr7,r3,r4 + bgt cr7,L(no_match) +- srdi r0,r4,3 /* Convert leading zeroes to bytes. */ ++#else ++ cntlzd r0,r10 /* Count leading zeros before c matches. */ ++ cmpld cr7,r11,r10 ++ bgt cr7,L(no_match) ++#endif ++ srdi r0,r0,3 /* Convert leading zeros to bytes. */ + add r3,r8,r0 /* Return address of the matching c byte + or null in case c was not found. */ + blr +@@ -137,9 +152,13 @@ L(null_match): + + /* Move the doublewords left and right to discard the bits that are + not part of the string and bring them back as zeros. */ +- ++#ifdef __LITTLE_ENDIAN__ ++ srd r5,r5,r6 ++ sld r5,r5,r6 ++#else + sld r5,r5,r6 + srd r5,r5,r6 ++#endif + cmpdi cr7,r5,0 /* If r10 == 0, no c or null bytes + have been found. */ + bne cr7,L(done_null) +@@ -194,7 +213,13 @@ L(loop_null): + 0xff in the same position as the null byte in the original + doubleword from the string. Use that to calculate the pointer. */ + L(done_null): ++#ifdef __LITTLE_ENDIAN__ ++ addi r0,r5,-1 ++ andc r0,r0,r5 ++ popcntd r0,r0 ++#else + cntlzd r0,r5 /* Count leading zeros before the match. */ ++#endif + srdi r0,r0,3 /* Convert leading zeros to bytes. */ + add r3,r8,r0 /* Return address of the matching null byte. */ + blr +Index: glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/power7/strchrnul.S +=================================================================== +--- glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/power7/strchrnul.S.orig ++++ glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/power7/strchrnul.S +@@ -29,8 +29,8 @@ ENTRY (BP_SYM(__strchrnul)) + 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 + + rlwinm r6,r3,3,26,28 /* Calculate padding. */ +@@ -46,10 +46,17 @@ ENTRY (BP_SYM(__strchrnul)) + + /* Move the doublewords left and right to discard the bits that are + not part of the string and to bring them back as zeros. */ ++#ifdef __LITTLE_ENDIAN__ ++ srd r10,r10,r6 ++ srd r9,r9,r6 ++ sld r10,r10,r6 ++ sld r9,r9,r6 ++#else + sld r10,r10,r6 + sld r9,r9,r6 + srd r10,r10,r6 + srd r9,r9,r6 ++#endif + or r5,r9,r10 /* OR the results to speed things up. */ + cmpdi cr7,r5,0 /* If r5 == 0, no c or null bytes + have been found. */ +@@ -99,7 +106,7 @@ L(loop): + bne cr6,L(done) + + /* The c/null byte must be in the second doubleword. Adjust the +- address again and move the result of cmpb to r10 so we can calculate ++ address again and move the result of cmpb to r5 so we can calculate + the pointer. */ + mr r5,r10 + addi r8,r8,8 +@@ -108,7 +115,13 @@ L(loop): + 0xff in the same position as the c/null byte in the original + doubleword from the string. Use that to calculate the pointer. */ + L(done): ++#ifdef __LITTLE_ENDIAN__ ++ addi r0,r5,-1 ++ andc r0,r0,r5 ++ popcntd r0,r0 ++#else + cntlzd r0,r5 /* Count leading zeros before the match. */ ++#endif + srdi r0,r0,3 /* Convert leading zeros to bytes. */ + add r3,r8,r0 /* Return address of matching c/null byte. */ + blr +Index: glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/strchr.S +=================================================================== +--- glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/strchr.S.orig ++++ glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/strchr.S +@@ -50,14 +50,16 @@ ENTRY (BP_SYM (strchr)) + #define rIGN r10 /* number of bits we should ignore in the first word */ + #define rMASK r11 /* mask with the bits to ignore set to 0 */ + #define rTMP3 r12 ++#define rTMP4 rIGN ++#define rTMP5 rMASK + + CHECK_BOUNDS_LOW (rSTR, rTMP1, rTMP2) + STORE_RETURN_BOUNDS (rTMP1, rTMP2) + + dcbt 0,rRTN +- rlwimi rCHR, rCHR, 8, 16, 23 ++ insrdi rCHR, rCHR, 8, 48 + li rMASK, -1 +- rlwimi rCHR, rCHR, 16, 0, 15 ++ insrdi rCHR, rCHR, 16, 32 + rlwinm rIGN, rRTN, 3, 26, 28 + insrdi rCHR, rCHR, 32, 0 + lis rFEFE, -0x101 +@@ -70,53 +72,74 @@ ENTRY (BP_SYM (strchr)) + add rFEFE, rFEFE, rTMP1 + /* Test the first (partial?) word. */ + ld rWORD, 0(rSTR) ++#ifdef __LITTLE_ENDIAN__ ++ sld rMASK, rMASK, rIGN ++#else + srd rMASK, rMASK, rIGN ++#endif + orc rWORD, rWORD, rMASK + add rTMP1, rFEFE, rWORD + nor rTMP2, r7F7F, rWORD +- and. rTMP1, rTMP1, rTMP2 ++ and. rTMP4, rTMP1, rTMP2 + xor rTMP3, rCHR, rWORD + orc rTMP3, rTMP3, rMASK + b L(loopentry) + + /* The loop. */ + +-L(loop):ldu rWORD, 8(rSTR) +- and. rTMP1, rTMP1, rTMP2 ++L(loop): ++ ldu rWORD, 8(rSTR) ++ and. rTMP5, rTMP1, rTMP2 + /* Test for 0. */ +- add rTMP1, rFEFE, rWORD +- nor rTMP2, r7F7F, rWORD ++ add rTMP1, rFEFE, rWORD /* x - 0x01010101. */ ++ nor rTMP2, r7F7F, rWORD /* ~(x | 0x7f7f7f7f) == ~x & 0x80808080. */ + bne L(foundit) +- and. rTMP1, rTMP1, rTMP2 ++ and. rTMP4, rTMP1, rTMP2 /* (x - 0x01010101) & ~x & 0x80808080. */ + /* Start test for the bytes we're looking for. */ + xor rTMP3, rCHR, rWORD + L(loopentry): + add rTMP1, rFEFE, rTMP3 + nor rTMP2, r7F7F, rTMP3 + beq L(loop) ++ + /* There is a zero byte in the word, but may also be a matching byte (either + before or after the zero byte). In fact, we may be looking for a +- zero byte, in which case we return a match. We guess that this hasn't +- happened, though. */ +-L(missed): +- and. rTMP1, rTMP1, rTMP2 ++ zero byte, in which case we return a match. */ ++ and. rTMP5, rTMP1, rTMP2 + li rRTN, 0 + STORE_RETURN_VALUE (rSTR) + beqlr +-/* It did happen. Decide which one was first... +- I'm not sure if this is actually faster than a sequence of +- rotates, compares, and branches (we use it anyway because it's shorter). */ ++/* At this point: ++ rTMP5 bytes are 0x80 for each match of c, 0 otherwise. ++ rTMP4 bytes are 0x80 for each match of 0, 0 otherwise. ++ But there may be false matches in the next most significant byte from ++ a true match due to carries. This means we need to recalculate the ++ matches using a longer method for big-endian. */ ++#ifdef __LITTLE_ENDIAN__ ++ addi rTMP1, rTMP5, -1 ++ andc rTMP1, rTMP1, rTMP5 ++ cntlzd rCLZB, rTMP1 ++ addi rTMP2, rTMP4, -1 ++ andc rTMP2, rTMP2, rTMP4 ++ cmpld rTMP1, rTMP2 ++ bgtlr ++ subfic rCLZB, rCLZB, 64-7 ++#else ++/* I think we could reduce this by two instructions by keeping the "nor" ++ results from the loop for reuse here. See strlen.S tail. Similarly ++ one instruction could be pruned from L(foundit). */ + and rFEFE, r7F7F, rWORD +- or rMASK, r7F7F, rWORD ++ or rTMP5, r7F7F, rWORD + and rTMP1, r7F7F, rTMP3 +- or rIGN, r7F7F, rTMP3 ++ or rTMP4, r7F7F, rTMP3 + add rFEFE, rFEFE, r7F7F + add rTMP1, rTMP1, r7F7F +- nor rWORD, rMASK, rFEFE +- nor rTMP2, rIGN, rTMP1 ++ nor rWORD, rTMP5, rFEFE ++ nor rTMP2, rTMP4, rTMP1 ++ cntlzd rCLZB, rTMP2 + cmpld rWORD, rTMP2 + bgtlr +- cntlzd rCLZB, rTMP2 ++#endif + srdi rCLZB, rCLZB, 3 + add rRTN, rSTR, rCLZB + CHECK_BOUNDS_HIGH_RTN (rSTR, rTMP2, tdlge) +@@ -124,13 +147,21 @@ L(missed): + blr + + L(foundit): ++#ifdef __LITTLE_ENDIAN__ ++ addi rTMP1, rTMP5, -1 ++ andc rTMP1, rTMP1, rTMP5 ++ cntlzd rCLZB, rTMP1 ++ subfic rCLZB, rCLZB, 64-7-64 ++ sradi rCLZB, rCLZB, 3 ++#else + and rTMP1, r7F7F, rTMP3 +- or rIGN, r7F7F, rTMP3 ++ or rTMP4, r7F7F, rTMP3 + add rTMP1, rTMP1, r7F7F +- nor rTMP2, rIGN, rTMP1 ++ nor rTMP2, rTMP4, rTMP1 + cntlzd rCLZB, rTMP2 + subi rSTR, rSTR, 8 + srdi rCLZB, rCLZB, 3 ++#endif + add rRTN, rSTR, rCLZB + CHECK_BOUNDS_HIGH_RTN (rSTR, rTMP2, tdlge) + STORE_RETURN_VALUE (rSTR) |