.
[glibc/history.git] / sysdeps / powerpc / powerpc64 / strlen.S
blob4c1385aead6864e5446d238bc02539948923457d
1 /* Optimized strlen implementation for PowerPC64.
2    Copyright (C) 1997, 1999, 2000, 2002, 2003 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 Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the 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    Lesser General Public License for more details.
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
20 #include <sysdep.h>
21 #include <bp-sym.h>
22 #include <bp-asm.h>
24 /* The algorithm here uses the following techniques:
26    1) Given a word 'x', we can test to see if it contains any 0 bytes
27       by subtracting 0x01010101, and seeing if any of the high bits of each
28       byte changed from 0 to 1. This works because the least significant
29       0 byte must have had no incoming carry (otherwise it's not the least
30       significant), so it is 0x00 - 0x01 == 0xff. For all other
31       byte values, either they have the high bit set initially, or when
32       1 is subtracted you get a value in the range 0x00-0x7f, none of which
33       have their high bit set. The expression here is
34       (x + 0xfefefeff) & ~(x | 0x7f7f7f7f), which gives 0x00000000 when
35       there were no 0x00 bytes in the word.
37    2) Given a word 'x', we can test to see _which_ byte was zero by
38       calculating ~(((x & 0x7f7f7f7f) + 0x7f7f7f7f) | x | 0x7f7f7f7f).
39       This produces 0x80 in each byte that was zero, and 0x00 in all
40       the other bytes. The '| 0x7f7f7f7f' clears the low 7 bits in each
41       byte, and the '| x' part ensures that bytes with the high bit set
42       produce 0x00. The addition will carry into the high bit of each byte
43       iff that byte had one of its low 7 bits set. We can then just see
44       which was the most significant bit set and divide by 8 to find how
45       many to add to the index.
46       This is from the book 'The PowerPC Compiler Writer's Guide',
47       by Steve Hoxey, Faraydon Karim, Bill Hay and Hank Warren.
49    We deal with strings not aligned to a word boundary by taking the
50    first word and ensuring that bytes not part of the string
51    are treated as nonzero. To allow for memory latency, we unroll the
52    loop a few times, being careful to ensure that we do not read ahead
53    across cache line boundaries.
55    Questions to answer:
56    1) How long are strings passed to strlen? If they're often really long,
57    we should probably use cache management instructions and/or unroll the
58    loop more. If they're often quite short, it might be better to use
59    fact (2) in the inner loop than have to recalculate it.
60    2) How popular are bytes with the high bit set? If they are very rare,
61    on some processors it might be useful to use the simpler expression
62    ~((x - 0x01010101) | 0x7f7f7f7f) (that is, on processors with only one
63    ALU), but this fails when any character has its high bit set.  
64    
65    Answer:
66    1) Added a Data Cache Block Touch early to prefetch the first 128 
67    byte cache line. Adding dcbt instructions to the loop would not be 
68    effective since most strings will be shorter than the cache line.*/
70 /* Some notes on register usage: Under the SVR4 ABI, we can use registers
71    0 and 3 through 12 (so long as we don't call any procedures) without
72    saving them. We can also use registers 14 through 31 if we save them.
73    We can't use r1 (it's the stack pointer), r2 nor r13 because the user
74    program may expect them to hold their usual value if we get sent
75    a signal. Integer parameters are passed in r3 through r10.
76    We can use condition registers cr0, cr1, cr5, cr6, and cr7 without saving
77    them, the others we must save.  */
79 /* int [r3] strlen (char *s [r3])  */
81 ENTRY (BP_SYM (strlen))
82         CALL_MCOUNT 1
84 #define rTMP1   r0
85 #define rRTN    r3      /* incoming STR arg, outgoing result */
86 #define rSTR    r4      /* current string position */
87 #define rPADN   r5      /* number of padding bits we prepend to the
88                            string to make it start at a word boundary */
89 #define rFEFE   r6      /* constant 0xfefefefefefefeff (-0x0101010101010101) */
90 #define r7F7F   r7      /* constant 0x7f7f7f7f7f7f7f7f */
91 #define rWORD1  r8      /* current string doubleword */
92 #define rWORD2  r9      /* next string doubleword */
93 #define rMASK   r9      /* mask for first string doubleword */
94 #define rTMP2   r10
95 #define rTMP3   r11
96 #define rTMP4   r12
98 /* Note:  The Bounded pointer support in this code is broken.  This code
99    was inherited from PPC32 and and that support was never completed.  
100    Current PPC gcc does not support -fbounds-check or -fbounded-pointers.
101    These artifacts are left in the code as a reminder in case we need
102    bounded pointer support in the future.  */
103         CHECK_BOUNDS_LOW (rRTN, rTMP1, rTMP2)
105         dcbt    0,rRTN
106         clrrdi  rSTR, rRTN, 3
107         lis     r7F7F, 0x7f7f
108         rlwinm  rPADN, rRTN, 3, 26, 28
109         ld      rWORD1, 0(rSTR)
110         addi    r7F7F, r7F7F, 0x7f7f
111         li      rMASK, -1
112         insrdi  r7F7F, r7F7F, 32, 0
113 /* That's the setup done, now do the first pair of doublewords.
114    We make an exception and use method (2) on the first two doublewords, 
115    to reduce overhead.  */
116         srd     rMASK, rMASK, rPADN
117         and     rTMP1, r7F7F, rWORD1
118         or      rTMP2, r7F7F, rWORD1
119         lis     rFEFE, -0x101
120         add     rTMP1, rTMP1, r7F7F
121         addi    rFEFE, rFEFE, -0x101
122         nor     rTMP1, rTMP2, rTMP1
123         and.    rWORD1, rTMP1, rMASK
124         mtcrf   0x01, rRTN
125         bne     L(done0)
126         sldi  rTMP1, rFEFE, 32
127         add  rFEFE, rFEFE, rTMP1
128 /* Are we now aligned to a doubleword boundary?  */
129         bt      28, L(loop)
131 /* Handle second doubleword of pair.  */
132         ldu     rWORD1, 8(rSTR)
133         and     rTMP1, r7F7F, rWORD1
134         or      rTMP2, r7F7F, rWORD1
135         add     rTMP1, rTMP1, r7F7F
136         nor.    rWORD1, rTMP2, rTMP1
137         bne     L(done0)
139 /* The loop.  */
141 L(loop):
142         ld      rWORD1, 8(rSTR)
143         ldu     rWORD2, 16(rSTR)
144         add     rTMP1, rFEFE, rWORD1
145         nor     rTMP2, r7F7F, rWORD1
146         and.    rTMP1, rTMP1, rTMP2
147         add     rTMP3, rFEFE, rWORD2
148         nor     rTMP4, r7F7F, rWORD2
149         bne     L(done1)
150         and.    rTMP1, rTMP3, rTMP4
151         beq     L(loop)
153         and     rTMP1, r7F7F, rWORD2
154         add     rTMP1, rTMP1, r7F7F
155         andc    rWORD1, rTMP4, rTMP1
156         b       L(done0)
158 L(done1):
159         and     rTMP1, r7F7F, rWORD1
160         subi    rSTR, rSTR, 8
161         add     rTMP1, rTMP1, r7F7F
162         andc    rWORD1, rTMP2, rTMP1
164 /* When we get to here, rSTR points to the first doubleword in the string that
165    contains a zero byte, and the most significant set bit in rWORD1 is in that
166    byte.  */
167 L(done0):
168         cntlzd  rTMP3, rWORD1
169         subf    rTMP1, rRTN, rSTR
170         srdi    rTMP3, rTMP3, 3
171         add     rRTN, rTMP1, rTMP3
172         /* GKM FIXME: check high bound.  */
173         blr
174 END (BP_SYM (strlen))
175 libc_hidden_builtin_def (strlen)