Update.
[glibc.git] / sysdeps / powerpc / strlen.S
blob18e76238c0b537d81a5494e587eae4628caa00fa
1 /* Optimized strlen implementation for PowerPC.
2    Copyright (C) 1997, 1999, 2000 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
20 #include <sysdep.h>
22 /* The algorithm here uses the following techniques:
24    1) Given a word 'x', we can test to see if it contains any 0 bytes
25       by subtracting 0x01010101, and seeing if any of the high bits of each
26       byte changed from 0 to 1. This works because the least significant
27       0 byte must have had no incoming carry (otherwise it's not the least
28       significant), so it is 0x00 - 0x01 == 0xff. For all other
29       byte values, either they have the high bit set initially, or when
30       1 is subtracted you get a value in the range 0x00-0x7f, none of which
31       have their high bit set. The expression here is
32       (x + 0xfefefeff) & ~(x | 0x7f7f7f7f), which gives 0x00000000 when
33       there were no 0x00 bytes in the word.
35    2) Given a word 'x', we can test to see _which_ byte was zero by
36       calculating ~(((x & 0x7f7f7f7f) + 0x7f7f7f7f) | x | 0x7f7f7f7f).
37       This produces 0x80 in each byte that was zero, and 0x00 in all
38       the other bytes. The '| 0x7f7f7f7f' clears the low 7 bits in each
39       byte, and the '| x' part ensures that bytes with the high bit set
40       produce 0x00. The addition will carry into the high bit of each byte
41       iff that byte had one of its low 7 bits set. We can then just see
42       which was the most significant bit set and divide by 8 to find how
43       many to add to the index.
44       This is from the book 'The PowerPC Compiler Writer's Guide',
45       by Steve Hoxey, Faraydon Karim, Bill Hay and Hank Warren.
47    We deal with strings not aligned to a word boundary by taking the
48    first word and ensuring that bytes not part of the string
49    are treated as nonzero. To allow for memory latency, we unroll the
50    loop a few times, being careful to ensure that we do not read ahead
51    across cache line boundaries.
53    Questions to answer:
54    1) How long are strings passed to strlen? If they're often really long,
55    we should probably use cache management instructions and/or unroll the
56    loop more. If they're often quite short, it might be better to use
57    fact (2) in the inner loop than have to recalculate it.
58    2) How popular are bytes with the high bit set? If they are very rare,
59    on some processors it might be useful to use the simpler expression
60    ~((x - 0x01010101) | 0x7f7f7f7f) (that is, on processors with only one
61    ALU), but this fails when any character has its high bit set.  */
63 /* Some notes on register usage: Under the SVR4 ABI, we can use registers
64    0 and 3 through 12 (so long as we don't call any procedures) without
65    saving them. We can also use registers 14 through 31 if we save them.
66    We can't use r1 (it's the stack pointer), r2 nor r13 because the user
67    program may expect them to hold their usual value if we get sent
68    a signal. Integer parameters are passed in r3 through r10.
69    We can use condition registers cr0, cr1, cr5, cr6, and cr7 without saving
70    them, the others we must save.  */
72 /* int [r3] strlen (char *s [r3])  */
74 ENTRY (strlen)
76 #define rTMP1   r0
77 #define rRTN    r3      /* incoming STR arg, outgoing result */
78 #define rSTR    r4      /* current string position */
79 #define rPADN   r5      /* number of padding bits we prepend to the
80                            string to make it start at a word boundary */
81 #define rFEFE   r6      /* constant 0xfefefeff (-0x01010101) */
82 #define r7F7F   r7      /* constant 0x7f7f7f7f */
83 #define rWORD1  r8      /* current string word */
84 #define rWORD2  r9      /* next string word */
85 #define rMASK   r9      /* mask for first string word */
86 #define rTMP2   r10
87 #define rTMP3   r11
88 #define rTMP4   r12
90         clrrwi  rSTR, rRTN, 2
91         lis     r7F7F, 0x7f7f
92         rlwinm  rPADN, rRTN, 3, 27, 28
93         lwz     rWORD1, 0(rSTR)
94         li      rMASK, -1
95         addi    r7F7F, r7F7F, 0x7f7f
96 /* That's the setup done, now do the first pair of words.
97    We make an exception and use method (2) on the first two words, to reduce
98    overhead.  */
99         srw     rMASK, rMASK, rPADN
100         and     rTMP1, r7F7F, rWORD1
101         or      rTMP2, r7F7F, rWORD1
102         add     rTMP1, rTMP1, r7F7F
103         nor     rTMP1, rTMP2, rTMP1
104         and.    rWORD1, rTMP1, rMASK
105         mtcrf   0x01, rRTN
106         bne     L(done0)
107         lis     rFEFE, -0x101
108         addi    rFEFE, rFEFE, -0x101
109 /* Are we now aligned to a doubleword boundary?  */
110         bt      29, L(loop)
112 /* Handle second word of pair.  */
113         lwzu    rWORD1, 4(rSTR)
114         and     rTMP1, r7F7F, rWORD1
115         or      rTMP2, r7F7F, rWORD1
116         add     rTMP1, rTMP1, r7F7F
117         nor.    rWORD1, rTMP2, rTMP1
118         bne     L(done0)
120 /* The loop.  */
122 L(loop):
123         lwz     rWORD1, 4(rSTR)
124         lwzu    rWORD2, 8(rSTR)
125         add     rTMP1, rFEFE, rWORD1
126         nor     rTMP2, r7F7F, rWORD1
127         and.    rTMP1, rTMP1, rTMP2
128         add     rTMP3, rFEFE, rWORD2
129         nor     rTMP4, r7F7F, rWORD2
130         bne     L(done1)
131         and.    rTMP1, rTMP3, rTMP4
132         beq     L(loop)
134         and     rTMP1, r7F7F, rWORD2
135         add     rTMP1, rTMP1, r7F7F
136         andc    rWORD1, rTMP4, rTMP1
137         b       L(done0)
139 L(done1):
140         and     rTMP1, r7F7F, rWORD1
141         subi    rSTR, rSTR, 4
142         add     rTMP1, rTMP1, r7F7F
143         andc    rWORD1, rTMP2, rTMP1
145 /* When we get to here, rSTR points to the first word in the string that
146    contains a zero byte, and the most significant set bit in rWORD1 is in that
147    byte.  */
148 L(done0):
149         cntlzw  rTMP3, rWORD1
150         subf    rTMP1, rRTN, rSTR
151         srwi    rTMP3, rTMP3, 3
152         add     rRTN, rTMP1, rTMP3
153         blr
154 END (strlen)