summaryrefslogtreecommitdiffstats
path: root/src/internal/bytealg/compare_386.s
blob: 27b660ccf7c526ac70be5f016695cb19238aa19c (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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#include "go_asm.h"
#include "textflag.h"

TEXT ·Compare(SB),NOSPLIT,$0-28
	MOVL	a_base+0(FP), SI
	MOVL	a_len+4(FP), BX
	MOVL	b_base+12(FP), DI
	MOVL	b_len+16(FP), DX
	LEAL	ret+24(FP), AX
	JMP	cmpbody<>(SB)

TEXT runtime·cmpstring(SB),NOSPLIT,$0-20
	MOVL	a_base+0(FP), SI
	MOVL	a_len+4(FP), BX
	MOVL	b_base+8(FP), DI
	MOVL	b_len+12(FP), DX
	LEAL	ret+16(FP), AX
	JMP	cmpbody<>(SB)

// input:
//   SI = a
//   DI = b
//   BX = alen
//   DX = blen
//   AX = address of return word (set to 1/0/-1)
TEXT cmpbody<>(SB),NOSPLIT,$0-0
	MOVL	DX, BP
	SUBL	BX, DX // DX = blen-alen
	JLE	2(PC)
	MOVL	BX, BP // BP = min(alen, blen)
	CMPL	SI, DI
	JEQ	allsame
	CMPL	BP, $4
	JB	small
#ifdef GO386_softfloat
	JMP	mediumloop
#endif
largeloop:
	CMPL	BP, $16
	JB	mediumloop
	MOVOU	(SI), X0
	MOVOU	(DI), X1
	PCMPEQB X0, X1
	PMOVMSKB X1, BX
	XORL	$0xffff, BX	// convert EQ to NE
	JNE	diff16	// branch if at least one byte is not equal
	ADDL	$16, SI
	ADDL	$16, DI
	SUBL	$16, BP
	JMP	largeloop

diff16:
	BSFL	BX, BX	// index of first byte that differs
	XORL	DX, DX
	MOVB	(SI)(BX*1), CX
	CMPB	CX, (DI)(BX*1)
	SETHI	DX
	LEAL	-1(DX*2), DX	// convert 1/0 to +1/-1
	MOVL	DX, (AX)
	RET

mediumloop:
	CMPL	BP, $4
	JBE	_0through4
	MOVL	(SI), BX
	MOVL	(DI), CX
	CMPL	BX, CX
	JNE	diff4
	ADDL	$4, SI
	ADDL	$4, DI
	SUBL	$4, BP
	JMP	mediumloop

_0through4:
	MOVL	-4(SI)(BP*1), BX
	MOVL	-4(DI)(BP*1), CX
	CMPL	BX, CX
	JEQ	allsame

diff4:
	BSWAPL	BX	// reverse order of bytes
	BSWAPL	CX
	XORL	BX, CX	// find bit differences
	BSRL	CX, CX	// index of highest bit difference
	SHRL	CX, BX	// move a's bit to bottom
	ANDL	$1, BX	// mask bit
	LEAL	-1(BX*2), BX // 1/0 => +1/-1
	MOVL	BX, (AX)
	RET

	// 0-3 bytes in common
small:
	LEAL	(BP*8), CX
	NEGL	CX
	JEQ	allsame

	// load si
	CMPB	SI, $0xfc
	JA	si_high
	MOVL	(SI), SI
	JMP	si_finish
si_high:
	MOVL	-4(SI)(BP*1), SI
	SHRL	CX, SI
si_finish:
	SHLL	CX, SI

	// same for di
	CMPB	DI, $0xfc
	JA	di_high
	MOVL	(DI), DI
	JMP	di_finish
di_high:
	MOVL	-4(DI)(BP*1), DI
	SHRL	CX, DI
di_finish:
	SHLL	CX, DI

	BSWAPL	SI	// reverse order of bytes
	BSWAPL	DI
	XORL	SI, DI	// find bit differences
	JEQ	allsame
	BSRL	DI, CX	// index of highest bit difference
	SHRL	CX, SI	// move a's bit to bottom
	ANDL	$1, SI	// mask bit
	LEAL	-1(SI*2), BX // 1/0 => +1/-1
	MOVL	BX, (AX)
	RET

	// all the bytes in common are the same, so we just need
	// to compare the lengths.
allsame:
	XORL	BX, BX
	XORL	CX, CX
	TESTL	DX, DX
	SETLT	BX	// 1 if alen > blen
	SETEQ	CX	// 1 if alen == blen
	LEAL	-1(CX)(BX*2), BX	// 1,0,-1 result
	MOVL	BX, (AX)
	RET