]>
Commit | Line | Data |
---|---|---|
2601bc18 WN |
1 | /* Copyright (C) 2010-2011,2013 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. | |
3 | ||
4 | The GNU C Library is free software; you can redistribute it and/or | |
5 | modify it under the terms of the GNU Lesser General Public | |
6 | License as published by the Free Software Foundation; either | |
7 | version 2.1 of the License, or (at your option) any later version. | |
8 | ||
9 | The GNU C Library is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 | Lesser General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU Lesser General Public | |
15 | License along with the GNU C Library. If not, see | |
16 | <http://www.gnu.org/licenses/>. */ | |
17 | ||
18 | /* | |
19 | Assumes: | |
20 | ARMv6T2, AArch32 | |
21 | ||
22 | */ | |
23 | ||
21bfcecf | 24 | #include <arm-features.h> /* This might #define NO_THUMB. */ |
2601bc18 WN |
25 | #include <sysdep.h> |
26 | ||
27 | #ifdef __ARMEB__ | |
28 | #define S2LO lsl | |
29 | #define S2HI lsr | |
30 | #else | |
31 | #define S2LO lsr | |
32 | #define S2HI lsl | |
33 | #endif | |
34 | ||
21bfcecf RM |
35 | #ifndef NO_THUMB |
36 | /* This code is best on Thumb. */ | |
2601bc18 | 37 | .thumb |
21bfcecf RM |
38 | #else |
39 | /* Using bne.w explicitly is desirable in Thumb mode because it helps | |
40 | align the following label without a nop. In ARM mode there is no | |
41 | such difference. */ | |
42 | .macro bne.w label | |
43 | bne \label | |
44 | .endm | |
45 | ||
46 | /* This clobbers the condition codes, which the real Thumb cbnz instruction | |
47 | does not do. But it doesn't matter for any of the uses here. */ | |
48 | .macro cbnz reg, label | |
49 | cmp \reg, #0 | |
50 | bne \label | |
51 | .endm | |
52 | #endif | |
2601bc18 WN |
53 | |
54 | /* Parameters and result. */ | |
55 | #define srcin r0 | |
56 | #define result r0 | |
57 | ||
58 | /* Internal variables. */ | |
59 | #define src r1 | |
60 | #define data1a r2 | |
61 | #define data1b r3 | |
62 | #define const_m1 r12 | |
63 | #define const_0 r4 | |
64 | #define tmp1 r4 /* Overlaps const_0 */ | |
65 | #define tmp2 r5 | |
66 | ||
67 | .text | |
68 | .p2align 6 | |
69 | ENTRY(strlen) | |
70 | pld [srcin, #0] | |
71 | strd r4, r5, [sp, #-8]! | |
72 | cfi_adjust_cfa_offset (8) | |
73 | cfi_rel_offset (r4, 0) | |
74 | cfi_rel_offset (r5, 4) | |
75 | cfi_remember_state | |
76 | bic src, srcin, #7 | |
77 | mvn const_m1, #0 | |
78 | ands tmp1, srcin, #7 /* (8 - bytes) to alignment. */ | |
79 | pld [src, #32] | |
80 | bne.w .Lmisaligned8 | |
81 | mov const_0, #0 | |
82 | mov result, #-8 | |
83 | .Lloop_aligned: | |
84 | /* Bytes 0-7. */ | |
85 | ldrd data1a, data1b, [src] | |
86 | pld [src, #64] | |
87 | add result, result, #8 | |
88 | .Lstart_realigned: | |
89 | uadd8 data1a, data1a, const_m1 /* Saturating GE<0:3> set. */ | |
90 | sel data1a, const_0, const_m1 /* Select based on GE<0:3>. */ | |
91 | uadd8 data1b, data1b, const_m1 | |
92 | sel data1b, data1a, const_m1 /* Only used if d1a == 0. */ | |
93 | cbnz data1b, .Lnull_found | |
94 | ||
95 | /* Bytes 8-15. */ | |
96 | ldrd data1a, data1b, [src, #8] | |
97 | uadd8 data1a, data1a, const_m1 /* Saturating GE<0:3> set. */ | |
98 | add result, result, #8 | |
99 | sel data1a, const_0, const_m1 /* Select based on GE<0:3>. */ | |
100 | uadd8 data1b, data1b, const_m1 | |
101 | sel data1b, data1a, const_m1 /* Only used if d1a == 0. */ | |
102 | cbnz data1b, .Lnull_found | |
103 | ||
104 | /* Bytes 16-23. */ | |
105 | ldrd data1a, data1b, [src, #16] | |
106 | uadd8 data1a, data1a, const_m1 /* Saturating GE<0:3> set. */ | |
107 | add result, result, #8 | |
108 | sel data1a, const_0, const_m1 /* Select based on GE<0:3>. */ | |
109 | uadd8 data1b, data1b, const_m1 | |
110 | sel data1b, data1a, const_m1 /* Only used if d1a == 0. */ | |
111 | cbnz data1b, .Lnull_found | |
112 | ||
113 | /* Bytes 24-31. */ | |
114 | ldrd data1a, data1b, [src, #24] | |
115 | add src, src, #32 | |
116 | uadd8 data1a, data1a, const_m1 /* Saturating GE<0:3> set. */ | |
117 | add result, result, #8 | |
118 | sel data1a, const_0, const_m1 /* Select based on GE<0:3>. */ | |
119 | uadd8 data1b, data1b, const_m1 | |
120 | sel data1b, data1a, const_m1 /* Only used if d1a == 0. */ | |
121 | cmp data1b, #0 | |
122 | beq .Lloop_aligned | |
123 | ||
124 | .Lnull_found: | |
125 | cmp data1a, #0 | |
126 | itt eq | |
127 | addeq result, result, #4 | |
128 | moveq data1a, data1b | |
129 | #ifndef __ARMEB__ | |
130 | rev data1a, data1a | |
131 | #endif | |
132 | clz data1a, data1a | |
133 | ldrd r4, r5, [sp], #8 | |
134 | cfi_adjust_cfa_offset (-8) | |
135 | cfi_restore (r4) | |
136 | cfi_restore (r5) | |
137 | add result, result, data1a, lsr #3 /* Bits -> Bytes. */ | |
138 | DO_RET(lr) | |
139 | ||
140 | .Lmisaligned8: | |
141 | cfi_restore_state | |
142 | ldrd data1a, data1b, [src] | |
143 | and tmp2, tmp1, #3 | |
144 | rsb result, tmp1, #0 | |
145 | lsl tmp2, tmp2, #3 /* Bytes -> bits. */ | |
146 | tst tmp1, #4 | |
147 | pld [src, #64] | |
148 | S2HI tmp2, const_m1, tmp2 | |
21bfcecf RM |
149 | #ifdef NO_THUMB |
150 | mvn tmp1, tmp2 | |
151 | orr data1a, data1a, tmp1 | |
152 | itt ne | |
153 | orrne data1b, data1b, tmp1 | |
154 | #else | |
2601bc18 WN |
155 | orn data1a, data1a, tmp2 |
156 | itt ne | |
157 | ornne data1b, data1b, tmp2 | |
21bfcecf | 158 | #endif |
2601bc18 WN |
159 | movne data1a, const_m1 |
160 | mov const_0, #0 | |
161 | b .Lstart_realigned | |
162 | ||
163 | END(strlen) | |
164 | libc_hidden_builtin_def (strlen) |