Update copyright dates with scripts/update-copyrights.
[glibc.git] / sysdeps / aarch64 / strcmp.S
blobe99d6625b73e890228d907d89115603c22d26b1e
1 /* Copyright (C) 2012-2017 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
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.
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.
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    <http://www.gnu.org/licenses/>.  */
19 /* Assumptions:
20  *
21  * ARMv8-a, AArch64
22  */
24 #include <sysdep.h>
26 #define REP8_01 0x0101010101010101
27 #define REP8_7f 0x7f7f7f7f7f7f7f7f
28 #define REP8_80 0x8080808080808080
30 /* Parameters and result.  */
31 #define src1            x0
32 #define src2            x1
33 #define result          x0
35 /* Internal variables.  */
36 #define data1           x2
37 #define data1w          w2
38 #define data2           x3
39 #define data2w          w3
40 #define has_nul         x4
41 #define diff            x5
42 #define syndrome        x6
43 #define tmp1            x7
44 #define tmp2            x8
45 #define tmp3            x9
46 #define zeroones        x10
47 #define pos             x11
49         /* Start of performance-critical section  -- one 64B cache line.  */
50 ENTRY_ALIGN(strcmp, 6)
52         DELOUSE (0)
53         DELOUSE (1)
54         eor     tmp1, src1, src2
55         mov     zeroones, #REP8_01
56         tst     tmp1, #7
57         b.ne    L(misaligned8)
58         ands    tmp1, src1, #7
59         b.ne    L(mutual_align)
60         /* NUL detection works on the principle that (X - 1) & (~X) & 0x80
61            (=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and
62            can be done in parallel across the entire word.  */
63 L(loop_aligned):
64         ldr     data1, [src1], #8
65         ldr     data2, [src2], #8
66 L(start_realigned):
67         sub     tmp1, data1, zeroones
68         orr     tmp2, data1, #REP8_7f
69         eor     diff, data1, data2      /* Non-zero if differences found.  */
70         bic     has_nul, tmp1, tmp2     /* Non-zero if NUL terminator.  */
71         orr     syndrome, diff, has_nul
72         cbz     syndrome, L(loop_aligned)
73         /* End of performance-critical section  -- one 64B cache line.  */
75 #ifndef __AARCH64EB__
76         rev     syndrome, syndrome
77         rev     data1, data1
78         /* The MS-non-zero bit of the syndrome marks either the first bit
79            that is different, or the top bit of the first zero byte.
80            Shifting left now will bring the critical information into the
81            top bits.  */
82         clz     pos, syndrome
83         rev     data2, data2
84         lsl     data1, data1, pos
85         lsl     data2, data2, pos
86         /* But we need to zero-extend (char is unsigned) the value and then
87            perform a signed 32-bit subtraction.  */
88         lsr     data1, data1, #56
89         sub     result, data1, data2, lsr #56
90         RET
91 #else
92         /* For big-endian we cannot use the trick with the syndrome value
93            as carry-propagation can corrupt the upper bits if the trailing
94            bytes in the string contain 0x01.  */
95         /* However, if there is no NUL byte in the dword, we can generate
96            the result directly.  We can't just subtract the bytes as the
97            MSB might be significant.  */
98         cbnz    has_nul, 1f
99         cmp     data1, data2
100         cset    result, ne
101         cneg    result, result, lo
102         RET
104         /* Re-compute the NUL-byte detection, using a byte-reversed value.  */
105         rev     tmp3, data1
106         sub     tmp1, tmp3, zeroones
107         orr     tmp2, tmp3, #REP8_7f
108         bic     has_nul, tmp1, tmp2
109         rev     has_nul, has_nul
110         orr     syndrome, diff, has_nul
111         clz     pos, syndrome
112         /* The MS-non-zero bit of the syndrome marks either the first bit
113            that is different, or the top bit of the first zero byte.
114            Shifting left now will bring the critical information into the
115            top bits.  */
116         lsl     data1, data1, pos
117         lsl     data2, data2, pos
118         /* But we need to zero-extend (char is unsigned) the value and then
119            perform a signed 32-bit subtraction.  */
120         lsr     data1, data1, #56
121         sub     result, data1, data2, lsr #56
122         RET
123 #endif
125 L(mutual_align):
126         /* Sources are mutually aligned, but are not currently at an
127            alignment boundary.  Round down the addresses and then mask off
128            the bytes that preceed the start point.  */
129         bic     src1, src1, #7
130         bic     src2, src2, #7
131         lsl     tmp1, tmp1, #3          /* Bytes beyond alignment -> bits.  */
132         ldr     data1, [src1], #8
133         neg     tmp1, tmp1              /* Bits to alignment -64.  */
134         ldr     data2, [src2], #8
135         mov     tmp2, #~0
136 #ifdef __AARCH64EB__
137         /* Big-endian.  Early bytes are at MSB.  */
138         lsl     tmp2, tmp2, tmp1        /* Shift (tmp1 & 63).  */
139 #else
140         /* Little-endian.  Early bytes are at LSB.  */
141         lsr     tmp2, tmp2, tmp1        /* Shift (tmp1 & 63).  */
142 #endif
143         orr     data1, data1, tmp2
144         orr     data2, data2, tmp2
145         b       L(start_realigned)
147 L(misaligned8):
148         /* We can do better than this.  */
149         ldrb    data1w, [src1], #1
150         ldrb    data2w, [src2], #1
151         cmp     data1w, #1
152         ccmp    data1w, data2w, #0, cs  /* NZCV = 0b0000.  */
153         b.eq    L(misaligned8)
154         sub     result, data1, data2
155         RET
156 END(strcmp)
157 libc_hidden_builtin_def (strcmp)