1/* Optimized strchrnul implementation for PowerPC64/POWER7 using cmpb insn.
2   Copyright (C) 2010-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#ifndef STRCHRNUL
22# define STRCHRNUL __strchrnul
23#endif
24/* int [r3] strchrnul (char *s [r3], int c [r4])  */
25	.machine  power7
26ENTRY_TOCLESS (STRCHRNUL)
27	CALL_MCOUNT 2
28	dcbt	0,r3
29	clrrdi	r8,r3,3	      /* Align the address to doubleword boundary.  */
30
31	/* Replicate byte to doubleword.  */
32	insrdi	r4,r4,8,48
33	insrdi	r4,r4,16,32
34	insrdi	r4,r4,32,0
35
36	rlwinm	r6,r3,3,26,28 /* Calculate padding.  */
37	ld	r12,0(r8)     /* Load doubleword from memory.  */
38	li	r0,0	      /* Doubleword with null chars to use
39				 with cmpb.  */
40
41	/* Now r4 has a doubleword of c bytes and r0 has
42	   a doubleword of null bytes.  */
43
44	cmpb	r10,r12,r0    /* Compare each byte against c byte.  */
45	cmpb	r9,r12,r4     /* Compare each byte against null byte.  */
46
47	/* Move the doublewords left and right to discard the bits that are
48	   not part of the string and to bring them back as zeros.  */
49#ifdef __LITTLE_ENDIAN__
50	srd	r10,r10,r6
51	srd	r9,r9,r6
52	sld	r10,r10,r6
53	sld	r9,r9,r6
54#else
55	sld	r10,r10,r6
56	sld	r9,r9,r6
57	srd	r10,r10,r6
58	srd	r9,r9,r6
59#endif
60	or	r5,r9,r10     /* OR the results to speed things up.  */
61	cmpdi	cr7,r5,0      /* If r5 == 0, no c or null bytes
62				 have been found.  */
63	bne	cr7,L(done)
64
65	mtcrf   0x01,r8
66
67	/* Are we now aligned to a quadword boundary?  If so, skip to
68	   the main loop.  Otherwise, go through the alignment code.  */
69
70	bt	28,L(loop)
71
72	/* Handle DWORD2 of pair.  */
73	ldu	r12,8(r8)
74	cmpb	r10,r12,r0
75	cmpb	r9,r12,r4
76	or	r5,r9,r10
77	cmpdi	cr7,r5,0
78	bne	cr7,L(done)
79	b	L(loop)	      /* We branch here (rather than falling through)
80				 to skip the nops due to heavy alignment
81				 of the loop below.  */
82
83	.p2align  5
84L(loop):
85	/* Load two doublewords, compare and merge in a
86	   single register for speed.  This is an attempt
87	   to speed up the null-checking process for bigger strings.  */
88	ld	r12,8(r8)
89	ldu     r11,16(r8)
90	cmpb	r10,r12,r0
91	cmpb	r9,r12,r4
92	cmpb	r6,r11,r0
93	cmpb	r7,r11,r4
94	or	r5,r9,r10
95	or	r10,r6,r7
96	or	r11,r5,r10
97	cmpdi	cr7,r11,0
98	beq	cr7,L(loop)
99
100	/* OK, one (or both) of the doublewords contains a c/null byte.  Check
101	   the first doubleword and decrement the address in case the first
102	   doubleword really contains a c/null byte.  */
103
104	cmpdi	cr6,r5,0
105	addi	r8,r8,-8
106	bne	cr6,L(done)
107
108	/* The c/null byte must be in the second doubleword.  Adjust the
109	   address again and move the result of cmpb to r5 so we can calculate
110	   the pointer.  */
111	mr	r5,r10
112	addi	r8,r8,8
113
114	/* r5 has the output of the cmpb instruction, that is, it contains
115	   0xff in the same position as the c/null byte in the original
116	   doubleword from the string.  Use that to calculate the pointer.  */
117L(done):
118#ifdef __LITTLE_ENDIAN__
119	addi    r0,r5,-1
120	andc    r0,r0,r5
121	popcntd	r0,r0
122#else
123	cntlzd	r0,r5	      /* Count leading zeros before the match.  */
124#endif
125	srdi	r0,r0,3	      /* Convert leading zeros to bytes.  */
126	add	r3,r8,r0      /* Return address of matching c/null byte.  */
127	blr
128END (STRCHRNUL)
129weak_alias (STRCHRNUL, strchrnul)
130libc_hidden_builtin_def (STRCHRNUL)
131