mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
runtime: implement eqstring in assembly.
BenchmarkCompareStringEqual 10.4 7.33 -29.52% BenchmarkCompareStringIdentical 3.99 3.67 -8.02% BenchmarkCompareStringSameLength 9.80 6.84 -30.20% BenchmarkCompareStringDifferentLength 1.09 0.95 -12.84% BenchmarkCompareStringBigUnaligned 75220 76071 +1.13% BenchmarkCompareStringBig 69843 74746 +7.02% LGTM=bradfitz, josharian R=golang-codereviews, bradfitz, josharian, dave, khr CC=golang-codereviews https://golang.org/cl/105280044
This commit is contained in:
parent
38eea5b2ad
commit
b36ed9056f
6 changed files with 131 additions and 12 deletions
|
|
@ -1096,6 +1096,28 @@ TEXT runtime·memeq(SB),NOSPLIT,$0-12
|
|||
MOVL count+8(FP), BX
|
||||
JMP runtime·memeqbody(SB)
|
||||
|
||||
// eqstring tests whether two strings are equal.
|
||||
// See runtime_test.go:eqstring_generic for
|
||||
// equivlaent Go code.
|
||||
TEXT runtime·eqstring(SB),NOSPLIT,$0-17
|
||||
MOVL s1len+4(FP), AX
|
||||
MOVL s2len+12(FP), BX
|
||||
CMPL AX, BX
|
||||
JNE different
|
||||
MOVL s1str+0(FP), SI
|
||||
MOVL s2str+8(FP), DI
|
||||
CMPL SI, DI
|
||||
JEQ same
|
||||
CALL runtime·memeqbody(SB)
|
||||
MOVB AX, v+16(FP)
|
||||
RET
|
||||
same:
|
||||
MOVB $1, v+16(FP)
|
||||
RET
|
||||
different:
|
||||
MOVB $0, v+16(FP)
|
||||
RET
|
||||
|
||||
TEXT bytes·Equal(SB),NOSPLIT,$0-25
|
||||
MOVL a_len+4(FP), BX
|
||||
MOVL b_len+16(FP), CX
|
||||
|
|
|
|||
|
|
@ -1058,6 +1058,28 @@ TEXT runtime·memeq(SB),NOSPLIT,$0-24
|
|||
MOVQ count+16(FP), BX
|
||||
JMP runtime·memeqbody(SB)
|
||||
|
||||
// eqstring tests whether two strings are equal.
|
||||
// See runtime_test.go:eqstring_generic for
|
||||
// equivlaent Go code.
|
||||
TEXT runtime·eqstring(SB),NOSPLIT,$0-33
|
||||
MOVQ s1len+8(FP), AX
|
||||
MOVQ s2len+24(FP), BX
|
||||
CMPQ AX, BX
|
||||
JNE different
|
||||
MOVQ s1str+0(FP), SI
|
||||
MOVQ s2str+16(FP), DI
|
||||
CMPQ SI, DI
|
||||
JEQ same
|
||||
CALL runtime·memeqbody(SB)
|
||||
MOVB AX, v+32(FP)
|
||||
RET
|
||||
same:
|
||||
MOVB $1, v+32(FP)
|
||||
RET
|
||||
different:
|
||||
MOVB $0, v+32(FP)
|
||||
RET
|
||||
|
||||
// a in SI
|
||||
// b in DI
|
||||
// count in BX
|
||||
|
|
|
|||
|
|
@ -715,6 +715,28 @@ TEXT runtime·memeq(SB),NOSPLIT,$0-12
|
|||
MOVL count+8(FP), BX
|
||||
JMP runtime·memeqbody(SB)
|
||||
|
||||
// eqstring tests whether two strings are equal.
|
||||
// See runtime_test.go:eqstring_generic for
|
||||
// equivlaent Go code.
|
||||
TEXT runtime·eqstring(SB),NOSPLIT,$0-17
|
||||
MOVL s1len+4(FP), AX
|
||||
MOVL s2len+12(FP), BX
|
||||
CMPL AX, BX
|
||||
JNE different
|
||||
MOVL s1str+0(FP), SI
|
||||
MOVL s2str+8(FP), DI
|
||||
CMPL SI, DI
|
||||
JEQ same
|
||||
CALL runtime·memeqbody(SB)
|
||||
MOVB AX, v+16(FP)
|
||||
RET
|
||||
same:
|
||||
MOVB $1, v+16(FP)
|
||||
RET
|
||||
different:
|
||||
MOVB $0, v+16(FP)
|
||||
RET
|
||||
|
||||
// a in SI
|
||||
// b in DI
|
||||
// count in BX
|
||||
|
|
|
|||
|
|
@ -646,6 +646,33 @@ _next:
|
|||
MOVW $0, R0
|
||||
RET
|
||||
|
||||
// eqstring tests whether two strings are equal.
|
||||
// See runtime_test.go:eqstring_generic for
|
||||
// equivlaent Go code.
|
||||
TEXT runtime·eqstring(SB),NOSPLIT,$-4-17
|
||||
MOVW s1len+4(FP), R0
|
||||
MOVW s2len+12(FP), R1
|
||||
MOVW $0, R7
|
||||
CMP R0, R1
|
||||
MOVB.NE R7, v+16(FP)
|
||||
RET.NE
|
||||
MOVW s1str+0(FP), R2
|
||||
MOVW s2str+8(FP), R3
|
||||
MOVW $1, R8
|
||||
MOVB R8, v+16(FP)
|
||||
CMP R2, R3
|
||||
RET.EQ
|
||||
ADD R2, R0, R6
|
||||
_eqnext:
|
||||
CMP R2, R6
|
||||
RET.EQ
|
||||
MOVBU.P 1(R2), R4
|
||||
MOVBU.P 1(R3), R5
|
||||
CMP R4, R5
|
||||
BEQ _eqnext
|
||||
MOVB R7, v+16(FP)
|
||||
RET
|
||||
|
||||
// We have to resort to TLS variable to save g(R10) and
|
||||
// m(R9). One reason is that external code might trigger
|
||||
// SIGSEGV, and our runtime.sigtramp don't even know we
|
||||
|
|
|
|||
|
|
@ -202,3 +202,41 @@ func testSetPanicOnFault(t *testing.T, addr uintptr) {
|
|||
println(*p)
|
||||
t.Fatalf("still here - should have faulted on address %#x", addr)
|
||||
}
|
||||
|
||||
func eqstring_generic(s1, s2 string) bool {
|
||||
if len(s1) != len(s2) {
|
||||
return false
|
||||
}
|
||||
// optimization in assembly versions:
|
||||
// if s1.str == s2.str { return true }
|
||||
for i := 0; i < len(s1); i++ {
|
||||
if s1[i] != s2[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func TestEqString(t *testing.T) {
|
||||
// This isn't really an exhaustive test of eqstring, it's
|
||||
// just a convenient way of documenting (via eqstring_generic)
|
||||
// what eqstring does.
|
||||
s := []string{
|
||||
"",
|
||||
"a",
|
||||
"c",
|
||||
"aaa",
|
||||
"ccc",
|
||||
"cccc"[:3], // same contents, different string
|
||||
"1234567890",
|
||||
}
|
||||
for _, s1 := range s {
|
||||
for _, s2 := range s {
|
||||
x := s1 == s2
|
||||
y := eqstring_generic(s1, s2)
|
||||
if x != y {
|
||||
t.Errorf(`eqstring("%s","%s") = %t, want %t`, s1, s2, x, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -206,18 +206,6 @@ func concatstrings(s Slice) (res String) {
|
|||
res = concatstring(s.len, (String*)s.array);
|
||||
}
|
||||
|
||||
func eqstring(s1 String, s2 String) (v bool) {
|
||||
if(s1.len != s2.len) {
|
||||
v = false;
|
||||
return;
|
||||
}
|
||||
if(s1.str == s2.str) {
|
||||
v = true;
|
||||
return;
|
||||
}
|
||||
v = runtime·memeq(s1.str, s2.str, s1.len);
|
||||
}
|
||||
|
||||
int32
|
||||
runtime·strcmp(byte *s1, byte *s2)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue