1/* Optimized strcmp implementation for PowerPC64.
2   Copyright (C) 1997-2022 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