arc: Merge ARCv2 string routines in generic ARC .S files
[uclibc-ng.git] / libc / string / arc / strcmp.S
blobad38d9e00c8a02c9555afa53495b12cf117ea025
1 /*
2  * Copyright (C) 2013, 2014-2015, 2017 Synopsys, Inc. (www.synopsys.com)
3  * Copyright (C) 2007 ARC International (UK) LTD
4  *
5  * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
6  */
8 #include <features.h>
9 #include <sysdep.h>
11 #if !defined(__ARC700__) && !defined(__ARCHS__)
12 #error "Neither ARC700 nor ARCHS is defined!"
13 #endif
15 ENTRY(strcmp)
17 #ifdef __ARC700__
18 /* This is optimized primarily for the ARC700.
19    It would be possible to speed up the loops by one cycle / word
20    respective one cycle / byte by forcing double source 1 alignment, unrolling
21    by a factor of two, and speculatively loading the second word / byte of
22    source 1; however, that would increase the overhead for loop setup / finish,
23    and strcmp might often terminate early.  */
25         or      r2,r0,r1
26         bmsk_s  r2,r2,1
27         brne    r2,0,.Lcharloop
28         mov_s   r12,0x01010101
29         ror     r5,r12
30 .Lwordloop:
31         ld.ab   r2,[r0,4]
32         ld.ab   r3,[r1,4]
33         nop_s
34         sub     r4,r2,r12
35         bic     r4,r4,r2
36         and     r4,r4,r5
37         brne    r4,0,.Lfound0
38         breq    r2,r3,.Lwordloop
39 #ifdef  __LITTLE_ENDIAN__
40         xor     r0,r2,r3        ; mask for difference
41         sub_s   r1,r0,1
42         bic_s   r0,r0,r1        ; mask for least significant difference bit
43         sub     r1,r5,r0
44         xor     r0,r5,r1        ; mask for least significant difference byte
45         and_s   r2,r2,r0
46         and_s   r3,r3,r0
47 #endif /* LITTLE ENDIAN */
48         cmp_s   r2,r3
49         mov_s   r0,1
50         j_s.d   [blink]
51         bset.lo r0,r0,31
53         .balign 4
54 #ifdef __LITTLE_ENDIAN__
55 .Lfound0:
56         xor     r0,r2,r3        ; mask for difference
57         or      r0,r0,r4        ; or in zero indicator
58         sub_s   r1,r0,1
59         bic_s   r0,r0,r1        ; mask for least significant difference bit
60         sub     r1,r5,r0
61         xor     r0,r5,r1        ; mask for least significant difference byte
62         and_s   r2,r2,r0
63         and_s   r3,r3,r0
64         sub.f   r0,r2,r3
65         mov.hi  r0,1
66         j_s.d   [blink]
67         bset.lo r0,r0,31
68 #else /* BIG ENDIAN */
69         /* The zero-detection above can mis-detect 0x01 bytes as zeroes
70            because of carry-propagateion from a lower significant zero byte.
71            We can compensate for this by checking that bit0 is zero.
72            This compensation is not necessary in the step where we
73            get a low estimate for r2, because in any affected bytes
74            we already have 0x00 or 0x01, which will remain unchanged
75            when bit 7 is cleared.  */
76         .balign 4
77 .Lfound0:
78         lsr     r0,r4,8
79         lsr_s   r1,r2
80         bic_s   r2,r2,r0        ; get low estimate for r2 and get ...
81         bic_s   r0,r0,r1        ; <this is the adjusted mask for zeros>
82         or_s    r3,r3,r0        ; ... high estimate r3 so that r2 > r3 will ...
83         cmp_s   r3,r2           ; ... be independent of trailing garbage
84         or_s    r2,r2,r0        ; likewise for r3 > r2
85         bic_s   r3,r3,r0
86         rlc     r0,0            ; r0 := r2 > r3 ? 1 : 0
87         cmp_s   r2,r3
88         j_s.d   [blink]
89         bset.lo r0,r0,31
90 #endif /* ENDIAN */
92         .balign 4
93 .Lcharloop:
94         ldb.ab  r2,[r0,1]
95         ldb.ab  r3,[r1,1]
96         nop_s
97         breq    r2,0,.Lcmpend
98         breq    r2,r3,.Lcharloop
99 .Lcmpend:
100         j_s.d   [blink]
101         sub     r0,r2,r3
102 #endif /* __ARC700__ */
104 #ifdef __ARCHS__
105         or      r2, r0, r1
106         bmsk_s  r2, r2, 1
107         brne    r2, 0, @.Lcharloop
109 ;;; s1 and s2 are word aligned
110         ld.ab   r2, [r0, 4]
112         mov_s   r12, 0x01010101
113         ror     r11, r12
114         .align  4
115 .LwordLoop:
116         ld.ab   r3, [r1, 4]
117         ;; Detect NULL char in str1
118         sub     r4, r2, r12
119         ld.ab   r5, [r0, 4]
120         bic     r4, r4, r2
121         and     r4, r4, r11
122         brne.d.nt       r4, 0, .LfoundNULL
123         ;; Check if the read locations are the same
124         cmp     r2, r3
125         beq.d   .LwordLoop
126         mov.eq  r2, r5
128         ;; A match is found, spot it out
129 #ifdef __LITTLE_ENDIAN__
130         swape   r3, r3
131         mov_s   r0, 1
132         swape   r2, r2
133 #else
134         mov_s   r0, 1
135 #endif
136         cmp_s   r2, r3
137         j_s.d   [blink]
138         bset.lo r0, r0, 31
140         .align 4
141 .LfoundNULL:
142 #ifdef __BIG_ENDIAN__
143         swape   r4, r4
144         swape   r2, r2
145         swape   r3, r3
146 #endif
147         ;; Find null byte
148         ffs     r0, r4
149         bmsk    r2, r2, r0
150         bmsk    r3, r3, r0
151         swape   r2, r2
152         swape   r3, r3
153         ;; make the return value
154         sub.f   r0, r2, r3
155         mov.hi  r0, 1
156         j_s.d   [blink]
157         bset.lo r0, r0, 31
159         .align 4
160 .Lcharloop:
161         ldb.ab  r2, [r0, 1]
162         ldb.ab  r3, [r1, 1]
163         nop
164         breq    r2, 0, .Lcmpend
165         breq    r2, r3, .Lcharloop
167         .align 4
168 .Lcmpend:
169         j_s.d   [blink]
170         sub     r0, r2, r3
171 #endif /* __ARCHS__ */
173 END(strcmp)
174 libc_hidden_def(strcmp)
176 #ifndef __UCLIBC_HAS_LOCALE__
177 strong_alias(strcmp,strcoll)
178 libc_hidden_def(strcoll)
179 #endif