1 // Copyright 2018 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 #include "go_asm.h"
6 #include "textflag.h"
7
8 TEXT ·Compare<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-56
9 // R0 = a_base (want in R0)
10 // R1 = a_len (want in R1)
11 // R2 = a_cap (unused)
12 // R3 = b_base (want in R2)
13 // R4 = b_len (want in R3)
14 // R5 = b_cap (unused)
15 MOVD R3, R2
16 MOVD R4, R3
17 B cmpbody<>(SB)
18
19 TEXT runtime·cmpstring<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-40
20 // R0 = a_base
21 // R1 = a_len
22 // R2 = b_base
23 // R3 = b_len
24 B cmpbody<>(SB)
25
26 // On entry:
27 // R0 points to the start of a
28 // R1 is the length of a
29 // R2 points to the start of b
30 // R3 is the length of b
31 //
32 // On exit:
33 // R0 is the result
34 // R4, R5, R6, R8, R9, R10 and V0-V11 are clobbered
35 TEXT cmpbody<>(SB),NOSPLIT|NOFRAME,$0-0
36 CMP R0, R2
37 BEQ samebytes // same starting pointers; compare lengths
38 CMP R1, R3
39 CSEL LT, R3, R1, R6 // R6 is min(R1, R3)
40
41 CBZ R6, samebytes
42 BIC $0x3f, R6, R10
43 CBZ R10, less_than_64 // length < 64, use scalar path
44 ADD R0, R10 // end of 64-byte chunks
45
46 // Process 64 bytes per iteration using NEON.
47 // Compare 4x16-byte chunks and reduce the result to a single byte.
48 // On mismatch, rewind and fall back to the scalar path.
49 PCALIGN $16
50 chunk64_loop:
51 VLD1.P (R0), [V0.D2, V1.D2, V2.D2, V3.D2]
52 VLD1.P (R2), [V4.D2, V5.D2, V6.D2, V7.D2]
53 VCMEQ V0.B16, V4.B16, V8.B16
54 VCMEQ V1.B16, V5.B16, V9.B16
55 VCMEQ V2.B16, V6.B16, V10.B16
56 VCMEQ V3.B16, V7.B16, V11.B16
57 VAND V8.B16, V9.B16, V8.B16
58 VAND V10.B16, V11.B16, V10.B16
59 VAND V8.B16, V10.B16, V8.B16
60 VUMINV V8.B16, V8
61 VMOV V8.B[0], R4
62 CBZ R4, neon_mismatch
63 CMP R10, R0
64 BNE chunk64_loop
65
66 AND $0x3f, R6, R6 // remaining 0-63 bytes
67 CBZ R6, samebytes
68
69 less_than_64:
70 // Scalar 16-byte loop for up to 63 bytes, then byte-level tail.
71 BIC $0xf, R6, R10
72 CBZ R10, small // length < 16
73 ADD R0, R10
74 PCALIGN $16
75 chunk16_loop:
76 LDP.P 16(R0), (R4, R8)
77 LDP.P 16(R2), (R5, R9)
78 CMP R4, R5
79 BNE cmp
80 CMP R8, R9
81 BNE cmpnext
82 CMP R10, R0
83 BNE chunk16_loop
84 AND $0xf, R6, R6
85 CBZ R6, samebytes
86 SUBS $8, R6
87 BLT tail
88 // the length of tail > 8 bytes
89 MOVD.P 8(R0), R4
90 MOVD.P 8(R2), R5
91 CMP R4, R5
92 BNE cmp
93 SUB $8, R6
94 // compare last 8 bytes
95 // tail always reads the final 8-byte window at R0+R6. R6 may be
96 // negative here, overlapping already-verified bytes, which is harmless.
97 tail:
98 MOVD (R0)(R6), R4
99 MOVD (R2)(R6), R5
100 CMP R4, R5
101 BEQ samebytes
102 cmp:
103 REV R4, R4
104 REV R5, R5
105 CMP R4, R5
106 ret:
107 MOVD $1, R0
108 CNEG HI, R0, R0
109 RET
110
111 neon_mismatch:
112 // A mismatch was found in the last 64-byte NEON chunk. Rewind both
113 // pointers and let the scalar path locate the first differing byte.
114 SUB $64, R0
115 SUB $64, R2
116 MOVD $64, R6
117 B less_than_64
118
119 small:
120 TBZ $3, R6, lt_8
121 MOVD (R0), R4
122 MOVD (R2), R5
123 CMP R4, R5
124 BNE cmp
125 SUBS $8, R6
126 BEQ samebytes
127 B tail
128 lt_8:
129 TBZ $2, R6, lt_4
130 MOVWU (R0), R4
131 MOVWU (R2), R5
132 CMPW R4, R5
133 BNE cmp
134 SUBS $4, R6
135 BEQ samebytes
136 ADD $4, R0
137 ADD $4, R2
138 lt_4:
139 TBZ $1, R6, lt_2
140 MOVHU (R0), R4
141 MOVHU (R2), R5
142 CMPW R4, R5
143 BNE cmp
144 ADD $2, R0
145 ADD $2, R2
146 lt_2:
147 TBZ $0, R6, samebytes
148 one:
149 MOVBU (R0), R4
150 MOVBU (R2), R5
151 CMPW R4, R5
152 BNE ret
153 samebytes:
154 CMP R3, R1
155 CSET NE, R0
156 CNEG LO, R0, R0
157 RET
158 cmpnext:
159 REV R8, R4
160 REV R9, R5
161 CMP R4, R5
162 B ret
163
View as plain text