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
|
MOVL count+8(FP), BX
|
||||||
JMP runtime·memeqbody(SB)
|
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
|
TEXT bytes·Equal(SB),NOSPLIT,$0-25
|
||||||
MOVL a_len+4(FP), BX
|
MOVL a_len+4(FP), BX
|
||||||
MOVL b_len+16(FP), CX
|
MOVL b_len+16(FP), CX
|
||||||
|
|
|
||||||
|
|
@ -1058,6 +1058,28 @@ TEXT runtime·memeq(SB),NOSPLIT,$0-24
|
||||||
MOVQ count+16(FP), BX
|
MOVQ count+16(FP), BX
|
||||||
JMP runtime·memeqbody(SB)
|
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
|
// a in SI
|
||||||
// b in DI
|
// b in DI
|
||||||
// count in BX
|
// count in BX
|
||||||
|
|
|
||||||
|
|
@ -715,6 +715,28 @@ TEXT runtime·memeq(SB),NOSPLIT,$0-12
|
||||||
MOVL count+8(FP), BX
|
MOVL count+8(FP), BX
|
||||||
JMP runtime·memeqbody(SB)
|
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
|
// a in SI
|
||||||
// b in DI
|
// b in DI
|
||||||
// count in BX
|
// count in BX
|
||||||
|
|
|
||||||
|
|
@ -646,6 +646,33 @@ _next:
|
||||||
MOVW $0, R0
|
MOVW $0, R0
|
||||||
RET
|
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
|
// We have to resort to TLS variable to save g(R10) and
|
||||||
// m(R9). One reason is that external code might trigger
|
// m(R9). One reason is that external code might trigger
|
||||||
// SIGSEGV, and our runtime.sigtramp don't even know we
|
// SIGSEGV, and our runtime.sigtramp don't even know we
|
||||||
|
|
|
||||||
|
|
@ -202,3 +202,41 @@ func testSetPanicOnFault(t *testing.T, addr uintptr) {
|
||||||
println(*p)
|
println(*p)
|
||||||
t.Fatalf("still here - should have faulted on address %#x", addr)
|
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);
|
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
|
int32
|
||||||
runtime·strcmp(byte *s1, byte *s2)
|
runtime·strcmp(byte *s1, byte *s2)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue