]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/powerpc/powerpc64/power8/strcmp.S
powerpc: Improve strcmp performance for shorter strings
[thirdparty/glibc.git] / sysdeps / powerpc / powerpc64 / power8 / strcmp.S
1 /* Optimized strcmp implementation for PowerPC64/POWER8.
2 Copyright (C) 2015-2017 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
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.
9
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.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
18
19 #include <sysdep.h>
20
21 /* Implements the function
22
23 size_t [r3] strcmp (const char *s1 [r3], const char *s2 [r4])
24
25 The implementation uses unaligned doubleword access to avoid specialized
26 code paths depending of data alignment. Although recent powerpc64 uses
27 64K as default, the page cross handling assumes minimum page size of
28 4k. */
29
30 EALIGN (strcmp, 4, 0)
31 li r0,0
32
33 /* Check if [s1]+16 or [s2]+16 will cross a 4K page boundary using
34 the code:
35
36 (((size_t) s1) % PAGE_SIZE > (PAGE_SIZE - ITER_SIZE))
37
38 with PAGE_SIZE being 4096 and ITER_SIZE begin 16. */
39
40 rldicl r7,r3,0,52
41 rldicl r9,r4,0,52
42 cmpldi cr7,r7,4096-16
43 bgt cr7,L(pagecross_check)
44 cmpldi cr5,r9,4096-16
45 bgt cr5,L(pagecross_check)
46
47 /* For short string up to 16 bytes, load both s1 and s2 using
48 unaligned dwords and compare. */
49 ld r8,0(r3)
50 ld r10,0(r4)
51 cmpb r12,r8,r0
52 cmpb r11,r8,r10
53 orc. r9,r12,r11
54 bne cr0,L(different_nocmpb)
55
56 ld r8,8(r3)
57 ld r10,8(r4)
58 cmpb r12,r8,r0
59 cmpb r11,r8,r10
60 orc. r9,r12,r11
61 bne cr0,L(different_nocmpb)
62
63 addi r7,r3,16
64 addi r4,r4,16
65
66 L(align_8b):
67 /* Now it has checked for first 16 bytes, align source1 to doubleword
68 and adjust source2 address. */
69 rldicl r9,r7,0,61 /* source1 alignment to doubleword */
70 subf r4,r9,r4 /* Adjust source2 address based on source1
71 alignment. */
72 rldicr r7,r7,0,60 /* Align source1 to doubleword. */
73
74 /* At this point, source1 alignment is 0 and source2 alignment is
75 between 0 and 7. Check is source2 alignment is 0, meaning both
76 sources have the same alignment. */
77 andi. r9,r4,0x7
78 bne cr0,L(loop_diff_align)
79
80 /* If both source1 and source2 are doubleword aligned, there is no
81 need for page boundary cross checks. */
82
83 ld r8,0(r7)
84 ld r10,0(r4)
85 cmpb r12,r8,r0
86 cmpb r11,r8,r10
87 orc. r9,r12,r11
88 bne cr0,L(different_nocmpb)
89
90 .align 4
91 L(loop_equal_align):
92 ld r8,8(r7)
93 ld r10,8(r4)
94 cmpb r12,r8,r0
95 cmpb r11,r8,r10
96 orc. r9,r12,r11
97 bne cr0,L(different_nocmpb)
98
99 ld r8,16(r7)
100 ld r10,16(r4)
101 cmpb r12,r8,r0
102 cmpb r11,r8,r10
103 orc. r9,r12,r11
104 bne cr0,L(different_nocmpb)
105
106 ldu r8,24(r7)
107 ldu r10,24(r4)
108 cmpb r12,r8,r0
109 cmpb r11,r8,r10
110 orc. r9,r12,r11
111 bne cr0,L(different_nocmpb)
112
113 b L(loop_equal_align)
114
115 /* A zero byte was found in r8 (s1 dword), r9 contains the cmpb
116 result and r10 the dword from s2. To code isolate the byte
117 up to end (including the '\0'), masking with 0xFF the remaining
118 ones:
119
120 #if __LITTLE_ENDIAN__
121 (__builtin_ffsl (x) - 1) = counting trailing zero bits
122 r9 = (__builtin_ffsl (r9) - 1) + 8;
123 r9 = -1UL << r9
124 #else
125 r9 = __builtin_clzl (r9) + 8;
126 r9 = -1UL >> r9
127 #endif
128 r8 = r8 | r9
129 r10 = r10 | r9 */
130
131 #ifdef __LITTLE_ENDIAN__
132 nor r9,r9,r9
133 L(different_nocmpb):
134 neg r3,r9
135 and r9,r9,r3
136 cntlzd r9,r9
137 subfic r9,r9,63
138 #else
139 not r9,r9
140 L(different_nocmpb):
141 cntlzd r9,r9
142 subfic r9,r9,56
143 #endif
144 srd r3,r8,r9
145 srd r10,r10,r9
146 rldicl r10,r10,0,56
147 rldicl r3,r3,0,56
148 subf r3,r10,r3
149 extsw r3,r3
150 blr
151
152 .align 4
153 L(pagecross_check):
154 subfic r9,r9,4096
155 subfic r7,r7,4096
156 cmpld cr7,r7,r9
157 bge cr7,L(pagecross)
158 mr r7,r9
159
160 /* If unaligned 16 bytes reads across a 4K page boundary, it uses
161 a simple byte a byte comparison until the page alignment for s1
162 is reached. */
163 L(pagecross):
164 add r7,r3,r7
165 subf r9,r3,r7
166 mtctr r9
167
168 .align 4
169 L(pagecross_loop):
170 /* Loads a byte from s1 and s2, compare if *s1 is equal to *s2
171 and if *s1 is '\0'. */
172 lbz r9,0(r3)
173 lbz r10,0(r4)
174 addi r3,r3,1
175 addi r4,r4,1
176 cmplw cr7,r9,r10
177 cmpdi cr5,r9,r0
178 bne cr7,L(pagecross_ne)
179 beq cr5,L(pagecross_nullfound)
180 bdnz L(pagecross_loop)
181 b L(align_8b)
182
183 .align 4
184 /* The unaligned read of source2 will cross a 4K page boundary,
185 and the different byte or NULL maybe be in the remaining page
186 bytes. Since it can not use the unaligned load, the algorithm
187 reads and compares 8 bytes to keep source1 doubleword aligned. */
188 L(check_source2_byte):
189 li r9,8
190 mtctr r9
191
192 .align 4
193 L(check_source2_byte_loop):
194 lbz r9,0(r7)
195 lbz r10,0(r4)
196 addi r7,r7,1
197 addi r4,r4,1
198 cmplw cr7,r9,10
199 cmpdi r5,r9,0
200 bne cr7,L(pagecross_ne)
201 beq cr5,L(pagecross_nullfound)
202 bdnz L(check_source2_byte_loop)
203
204 /* If source2 is unaligned to doubleword, the code needs to check
205 on each interation if the unaligned doubleword access will cross
206 a 4k page boundary. */
207 .align 5
208 L(loop_unaligned):
209 ld r8,0(r7)
210 ld r10,0(r4)
211 cmpb r12,r8,r0
212 cmpb r11,r8,r10
213 orc. r9,r12,r11
214 bne cr0,L(different_nocmpb)
215 addi r7,r7,8
216 addi r4,r4,8
217
218 L(loop_diff_align):
219 /* Check if [src2]+8 cross a 4k page boundary:
220
221 srcin2 % PAGE_SIZE > (PAGE_SIZE - 8)
222
223 with PAGE_SIZE being 4096. */
224 rldicl r9,r4,0,52
225 cmpldi cr7,r9,4088
226 ble cr7,L(loop_unaligned)
227 b L(check_source2_byte)
228
229 .align 4
230 L(pagecross_ne):
231 extsw r3,r9
232 mr r9,r10
233 L(pagecross_retdiff):
234 subf r9,r9,r3
235 extsw r3,r9
236 blr
237
238 .align 4
239 L(pagecross_nullfound):
240 li r3,0
241 b L(pagecross_retdiff)
242 END (strcmp)
243 libc_hidden_builtin_def (strcmp)