summaryrefslogtreecommitdiff
path: root/common/lib/libc/arch/i386/string/strrchr.S
blob: 50593e45af988d1e3f78a731cf1b53a0d300b4cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/*
 * Written by J.T. Conklin <jtc@acorntoolworks.com>
 * Public domain.
 */

#include <machine/asm.h>

#if defined(LIBC_SCCS)
	RCSID("$NetBSD: strrchr.S,v 1.3 2014/03/22 19:38:46 jakllsch Exp $")
#endif

ENTRY(strrchr)
	pushl	%esi
	pushl	%edi
	pushl	%ebx
	movl	16(%esp),%edx
	movzbl	20(%esp),%ecx

	/* zero return value */
	xorl	%eax,%eax

	/*
	 * Align to word boundary.
	 * Consider unrolling loop?
	 */
.Lalign:
	testb	$3,%dl
	je	.Lword_aligned
	movb	(%edx),%bl
	cmpb	%cl,%bl
	jne	1f
	movl	%edx,%eax
1:	testb	%bl,%bl
	je	.Ldone
	incl	%edx
	jmp	.Lalign

.Lword_aligned:
	/* copy char to all bytes in word */
	movb	%cl,%ch
	movl	%ecx,%edi
	sall	$16,%ecx
	orl	%edi,%ecx

	/* Check whether any byte in the word is equal to ch or 0.  */
	_ALIGN_TEXT
.Lloop:
	movl	(%edx),%ebx
	addl	$4,%edx
	movl	%ebx,%esi
	leal	-0x01010101(%ebx),%edi
	xorl	%ecx,%esi
	subl	$0x01010101,%esi
	orl	%esi,%edi
	testl	$0x80808080,%edi
	je	.Lloop

	/*
	 * In rare cases, the above loop may exit prematurely. We must
	 * return to the loop if none of the bytes in the word match
	 * ch or are equal to 0.
	 */

	_ALIGN_TEXT
	cmpb	%cl,%bl		/* 1st byte == ch? */
	jne	1f
	leal	-4(%edx),%eax
1:	testb	%bl,%bl		/* 1st byte == 0? */
	je	.Ldone

	cmpb	%cl,%bh		/* 2nd byte == ch? */
	jne	1f
	leal	-3(%edx),%eax
1:	testb	%bh,%bh		/* 2nd byte == 0? */
	je	.Ldone

	shrl	$16,%ebx
	cmpb	%cl,%bl		/* 3rd byte == ch? */
	jne	1f
	leal	-2(%edx),%eax
1:	testb	%bl,%bl		/* 3rd byte == 0? */
	je	.Ldone

	cmpb	%cl,%bh		/* 4th byte == ch? */
	jne	1f
	leal	-1(%edx),%eax
1:	testb	%bh,%bh		/* 4th byte == 0? */
	jne	.Lloop

.Ldone:
	popl	%ebx
	popl	%edi
	popl	%esi
	ret
END(strrchr)

STRONG_ALIAS(rindex,strrchr)