1/* Optimized strcmp implementation for PowerPC64.
2 Copyright (C) 1997-2024 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 <https://www.gnu.org/licenses/>. */
18
19#include <sysdep.h>
20
21/* See strlen.s for comments on how the end-of-string testing works. */
22
23/* int [r3] strcmp (const char *s1 [r3], const char *s2 [r4]) */
24
25#ifndef STRCMP
26# define STRCMP strcmp
27#endif
28
29ENTRY_TOCLESS (STRCMP, 4)
30 CALL_MCOUNT 2
31
32#define rTMP2 r0
33#define rRTN r3
34#define rSTR1 r3 /* first string arg */
35#define rSTR2 r4 /* second string arg */
36#define rWORD1 r5 /* current word in s1 */
37#define rWORD2 r6 /* current word in s2 */
38#define rFEFE r7 /* constant 0xfefefefefefefeff (-0x0101010101010101) */
39#define r7F7F r8 /* constant 0x7f7f7f7f7f7f7f7f */
40#define rNEG r9 /* ~(word in s1 | 0x7f7f7f7f7f7f7f7f) */
41#define rBITDIF r10 /* bits that differ in s1 & s2 words */
42#define rTMP r11
43
44 dcbt 0,rSTR1
45 or rTMP, rSTR2, rSTR1
46 dcbt 0,rSTR2
47 clrldi. rTMP, rTMP, 61
48 lis rFEFE, -0x101
49 bne L(unaligned)
50
51 ld rWORD1, 0(rSTR1)
52 ld rWORD2, 0(rSTR2)
53 lis r7F7F, 0x7f7f
54 addi rFEFE, rFEFE, -0x101
55 addi r7F7F, r7F7F, 0x7f7f
56 sldi rTMP, rFEFE, 32
57 insrdi r7F7F, r7F7F, 32, 0
58 add rFEFE, rFEFE, rTMP
59 b L(g1)
60
61L(g0): ldu rWORD1, 8(rSTR1)
62 bne cr1, L(different)
63 ldu rWORD2, 8(rSTR2)
64L(g1): add rTMP, rFEFE, rWORD1
65 nor rNEG, r7F7F, rWORD1
66 and. rTMP, rTMP, rNEG
67 cmpd cr1, rWORD1, rWORD2
68 beq+ L(g0)
69
70/* OK. We've hit the end of the string. We need to be careful that
71 we don't compare two strings as different because of gunk beyond
72 the end of the strings... */
73#ifdef __LITTLE_ENDIAN__
74L(endstring):
75 addi rTMP2, rTMP, -1
76 beq cr1, L(equal)
77 andc rTMP2, rTMP2, rTMP
78 rldimi rTMP2, rTMP2, 1, 0
79 and rWORD2, rWORD2, rTMP2 /* Mask off gunk. */
80 and rWORD1, rWORD1, rTMP2
81 cmpd cr1, rWORD1, rWORD2
82 beq cr1, L(equal)
83 xor rBITDIF, rWORD1, rWORD2 /* rBITDIF has bits that differ. */
84 neg rNEG, rBITDIF
85 and rNEG, rNEG, rBITDIF /* rNEG has LS bit that differs. */
86 cntlzd rNEG, rNEG /* bitcount of the bit. */
87 andi. rNEG, rNEG, 56 /* bitcount to LS byte that differs. */
88 sld rWORD1, rWORD1, rNEG /* shift left to clear MS bytes. */
89 sld rWORD2, rWORD2, rNEG
90 xor. rBITDIF, rWORD1, rWORD2
91 sub rRTN, rWORD1, rWORD2
92 blt- L(highbit)
93 sradi rRTN, rRTN, 63 /* must return an int. */
94 ori rRTN, rRTN, 1
95 blr
96L(equal):
97 li rRTN, 0
98 blr
99
100L(different):
101 ld rWORD1, -8(rSTR1)
102 xor rBITDIF, rWORD1, rWORD2 /* rBITDIF has bits that differ. */
103 neg rNEG, rBITDIF
104 and rNEG, rNEG, rBITDIF /* rNEG has LS bit that differs. */
105 cntlzd rNEG, rNEG /* bitcount of the bit. */
106 andi. rNEG, rNEG, 56 /* bitcount to LS byte that differs. */
107 sld rWORD1, rWORD1, rNEG /* shift left to clear MS bytes. */
108 sld rWORD2, rWORD2, rNEG
109 xor. rBITDIF, rWORD1, rWORD2
110 sub rRTN, rWORD1, rWORD2
111 blt- L(highbit)
112 sradi rRTN, rRTN, 63
113 ori rRTN, rRTN, 1
114 blr
115L(highbit):
116 sradi rRTN, rWORD2, 63
117 ori rRTN, rRTN, 1
118 blr
119
120#else
121L(endstring):
122 and rTMP, r7F7F, rWORD1
123 beq cr1, L(equal)
124 add rTMP, rTMP, r7F7F
125 xor. rBITDIF, rWORD1, rWORD2
126 andc rNEG, rNEG, rTMP
127 blt- L(highbit)
128 cntlzd rBITDIF, rBITDIF
129 cntlzd rNEG, rNEG
130 addi rNEG, rNEG, 7
131 cmpd cr1, rNEG, rBITDIF
132 sub rRTN, rWORD1, rWORD2
133 blt- cr1, L(equal)
134 sradi rRTN, rRTN, 63 /* must return an int. */
135 ori rRTN, rRTN, 1
136 blr
137L(equal):
138 li rRTN, 0
139 blr
140
141L(different):
142 ld rWORD1, -8(rSTR1)
143 xor. rBITDIF, rWORD1, rWORD2
144 sub rRTN, rWORD1, rWORD2
145 blt- L(highbit)
146 sradi rRTN, rRTN, 63
147 ori rRTN, rRTN, 1
148 blr
149L(highbit):
150 sradi rRTN, rWORD2, 63
151 ori rRTN, rRTN, 1
152 blr
153#endif
154
155/* Oh well. In this case, we just do a byte-by-byte comparison. */
156 .align 4
157L(unaligned):
158 lbz rWORD1, 0(rSTR1)
159 lbz rWORD2, 0(rSTR2)
160 b L(u1)
161
162L(u0): lbzu rWORD1, 1(rSTR1)
163 bne- L(u4)
164 lbzu rWORD2, 1(rSTR2)
165L(u1): cmpwi cr1, rWORD1, 0
166 beq- cr1, L(u3)
167 cmpd rWORD1, rWORD2
168 bne- L(u3)
169 lbzu rWORD1, 1(rSTR1)
170 lbzu rWORD2, 1(rSTR2)
171 cmpdi cr1, rWORD1, 0
172 cmpd rWORD1, rWORD2
173 bne+ cr1, L(u0)
174L(u3): sub rRTN, rWORD1, rWORD2
175 blr
176L(u4): lbz rWORD1, -1(rSTR1)
177 sub rRTN, rWORD1, rWORD2
178 blr
179END (STRCMP)
180libc_hidden_builtin_def (strcmp)
181

source code of glibc/sysdeps/powerpc/powerpc64/strcmp.S