Skip to content

Commit 3216e0c

Browse files
committed
cmd/compile: replace eqstring with memequal
eqstring is only called for strings with equal lengths. Instead of pushing a pointer and length for each argument string on the stack we can omit pushing one of the lengths on the stack. Changing eqstrings signature to eqstring(*uint8, *uint8, int) bool to implement the above optimization would make it very similar to the existing memequal(*any, *any, uintptr) bool function. Since string lengths are positive we can avoid code redundancy and use memequal instead of using eqstring with an optimized signature. go command binary size reduced by 4128 bytes on amd64. name old time/op new time/op delta CompareStringEqual 6.03ns ± 1% 5.71ns ± 1% -5.23% (p=0.000 n=19+18) CompareStringIdentical 2.88ns ± 1% 3.22ns ± 7% +11.86% (p=0.000 n=20+20) CompareStringSameLength 4.31ns ± 1% 4.01ns ± 1% -7.17% (p=0.000 n=19+19) CompareStringDifferentLength 0.29ns ± 2% 0.29ns ± 2% ~ (p=1.000 n=20+20) CompareStringBigUnaligned 64.3µs ± 2% 64.1µs ± 3% ~ (p=0.164 n=20+19) CompareStringBig 61.9µs ± 1% 61.6µs ± 2% -0.46% (p=0.033 n=20+19) Change-Id: Ice15f3b937c981f0d3bc8479a9ea0d10658ac8df Reviewed-on: https://go-review.googlesource.com/53650 Run-TryBot: Martin Möhrmann <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Keith Randall <[email protected]>
1 parent d05a123 commit 3216e0c

14 files changed

+201
-378
lines changed

src/cmd/compile/internal/gc/builtin.go

Lines changed: 181 additions & 183 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/cmd/compile/internal/gc/builtin/runtime.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ func concatstring5(*[32]byte, string, string, string, string, string) string
4848
func concatstrings(*[32]byte, []string) string
4949

5050
func cmpstring(string, string) int
51-
func eqstring(string, string) bool
5251
func intstring(*[4]byte, int64) string
5352
func slicebytetostring(*[32]byte, []byte) string
5453
func slicebytetostringtmp([]byte) string

src/cmd/compile/internal/gc/walk.go

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,18 +1369,27 @@ opswitch:
13691369
n.Left = cheapexpr(n.Left, init)
13701370
n.Right = cheapexpr(n.Right, init)
13711371

1372-
r = mkcall("eqstring", types.Types[TBOOL], init, conv(n.Left, types.Types[TSTRING]), conv(n.Right, types.Types[TSTRING]))
1373-
1374-
// quick check of len before full compare for == or !=
1375-
// eqstring assumes that the lengths are equal
1372+
lstr := conv(n.Left, types.Types[TSTRING])
1373+
rstr := conv(n.Right, types.Types[TSTRING])
1374+
lptr := nod(OSPTR, lstr, nil)
1375+
rptr := nod(OSPTR, rstr, nil)
1376+
llen := conv(nod(OLEN, lstr, nil), types.Types[TUINTPTR])
1377+
rlen := conv(nod(OLEN, rstr, nil), types.Types[TUINTPTR])
1378+
1379+
fn := syslook("memequal")
1380+
fn = substArgTypes(fn, types.Types[TUINT8], types.Types[TUINT8])
1381+
r = mkcall1(fn, types.Types[TBOOL], init, lptr, rptr, llen)
1382+
1383+
// quick check of len before full compare for == or !=.
1384+
// memequal then tests equality up to length len.
13761385
// TODO(marvin): Fix Node.EType type union.
13771386
if Op(n.Etype) == OEQ {
1378-
// len(left) == len(right) && eqstring(left, right)
1379-
r = nod(OANDAND, nod(OEQ, nod(OLEN, n.Left, nil), nod(OLEN, n.Right, nil)), r)
1387+
// len(left) == len(right) && memequal(left, right, len)
1388+
r = nod(OANDAND, nod(OEQ, llen, rlen), r)
13801389
} else {
1381-
// len(left) != len(right) || !eqstring(left, right)
1390+
// len(left) != len(right) || !memequal(left, right, len)
13821391
r = nod(ONOT, r, nil)
1383-
r = nod(OOROR, nod(ONE, nod(OLEN, n.Left, nil), nod(OLEN, n.Right, nil)), r)
1392+
r = nod(OOROR, nod(ONE, llen, rlen), r)
13841393
}
13851394

13861395
r = typecheck(r, Erv)

src/runtime/asm_386.s

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,23 +1306,6 @@ eq:
13061306
MOVB $1, ret+8(FP)
13071307
RET
13081308

1309-
// eqstring tests whether two strings are equal.
1310-
// The compiler guarantees that strings passed
1311-
// to eqstring have equal length.
1312-
// See runtime_test.go:eqstring_generic for
1313-
// equivalent Go code.
1314-
TEXT runtime·eqstring(SB),NOSPLIT,$0-17
1315-
MOVL s1_base+0(FP), SI
1316-
MOVL s2_base+8(FP), DI
1317-
CMPL SI, DI
1318-
JEQ same
1319-
MOVL s1_len+4(FP), BX
1320-
LEAL ret+16(FP), AX
1321-
JMP runtime·memeqbody(SB)
1322-
same:
1323-
MOVB $1, ret+16(FP)
1324-
RET
1325-
13261309
TEXT bytes·Equal(SB),NOSPLIT,$0-25
13271310
MOVL a_len+4(FP), BX
13281311
MOVL b_len+16(FP), CX

src/runtime/asm_amd64.s

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,23 +1326,6 @@ eq:
13261326
MOVB $1, ret+16(FP)
13271327
RET
13281328

1329-
// eqstring tests whether two strings are equal.
1330-
// The compiler guarantees that strings passed
1331-
// to eqstring have equal length.
1332-
// See runtime_test.go:eqstring_generic for
1333-
// equivalent Go code.
1334-
TEXT runtime·eqstring(SB),NOSPLIT,$0-33
1335-
MOVQ s1_base+0(FP), SI
1336-
MOVQ s2_base+16(FP), DI
1337-
CMPQ SI, DI
1338-
JEQ eq
1339-
MOVQ s1_len+8(FP), BX
1340-
LEAQ ret+32(FP), AX
1341-
JMP runtime·memeqbody(SB)
1342-
eq:
1343-
MOVB $1, ret+32(FP)
1344-
RET
1345-
13461329
// a in SI
13471330
// b in DI
13481331
// count in BX

src/runtime/asm_amd64p32.s

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -641,24 +641,6 @@ eq:
641641
MOVB $1, ret+8(FP)
642642
RET
643643

644-
// eqstring tests whether two strings are equal.
645-
// The compiler guarantees that strings passed
646-
// to eqstring have equal length.
647-
// See runtime_test.go:eqstring_generic for
648-
// equivalent Go code.
649-
TEXT runtime·eqstring(SB),NOSPLIT,$0-17
650-
MOVL s1_base+0(FP), SI
651-
MOVL s2_base+8(FP), DI
652-
CMPL SI, DI
653-
JEQ same
654-
MOVL s1_len+4(FP), BX
655-
CALL runtime·memeqbody(SB)
656-
MOVB AX, ret+16(FP)
657-
RET
658-
same:
659-
MOVB $1, ret+16(FP)
660-
RET
661-
662644
// a in SI
663645
// b in DI
664646
// count in BX

src/runtime/asm_arm.s

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -813,31 +813,6 @@ samebytes:
813813
MOVW R0, (R7)
814814
RET
815815

816-
// eqstring tests whether two strings are equal.
817-
// The compiler guarantees that strings passed
818-
// to eqstring have equal length.
819-
// See runtime_test.go:eqstring_generic for
820-
// equivalent Go code.
821-
TEXT runtime·eqstring(SB),NOSPLIT,$-4-17
822-
MOVW s1_base+0(FP), R2
823-
MOVW s2_base+8(FP), R3
824-
MOVW $1, R8
825-
MOVB R8, ret+16(FP)
826-
CMP R2, R3
827-
RET.EQ
828-
MOVW s1_len+4(FP), R0
829-
ADD R2, R0, R6
830-
loop:
831-
CMP R2, R6
832-
RET.EQ
833-
MOVBU.P 1(R2), R4
834-
MOVBU.P 1(R3), R5
835-
CMP R4, R5
836-
BEQ loop
837-
MOVW $0, R8
838-
MOVB R8, ret+16(FP)
839-
RET
840-
841816
// TODO: share code with memequal?
842817
TEXT bytes·Equal(SB),NOSPLIT,$0-25
843818
MOVW a_len+4(FP), R1

src/runtime/asm_arm64.s

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -806,31 +806,6 @@ samebytes:
806806
MOVD R4, (R7)
807807
RET
808808

809-
// eqstring tests whether two strings are equal.
810-
// The compiler guarantees that strings passed
811-
// to eqstring have equal length.
812-
// See runtime_test.go:eqstring_generic for
813-
// equivalent Go code.
814-
TEXT runtime·eqstring(SB),NOSPLIT,$0-33
815-
MOVD s1_base+0(FP), R0
816-
MOVD s1_len+8(FP), R1
817-
MOVD s2_base+16(FP), R2
818-
ADD R0, R1 // end
819-
loop:
820-
CMP R0, R1
821-
BEQ equal // reaches the end
822-
MOVBU.P 1(R0), R4
823-
MOVBU.P 1(R2), R5
824-
CMP R4, R5
825-
BEQ loop
826-
notequal:
827-
MOVB ZR, ret+32(FP)
828-
RET
829-
equal:
830-
MOVD $1, R0
831-
MOVB R0, ret+32(FP)
832-
RET
833-
834809
//
835810
// functions for other packages
836811
//

src/runtime/asm_mips64x.s

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -679,31 +679,6 @@ eq:
679679
MOVB R1, ret+16(FP)
680680
RET
681681

682-
// eqstring tests whether two strings are equal.
683-
// The compiler guarantees that strings passed
684-
// to eqstring have equal length.
685-
// See runtime_test.go:eqstring_generic for
686-
// equivalent Go code.
687-
TEXT runtime·eqstring(SB),NOSPLIT,$0-33
688-
MOVV s1_base+0(FP), R1
689-
MOVV s2_base+16(FP), R2
690-
MOVV $1, R3
691-
MOVB R3, ret+32(FP)
692-
BNE R1, R2, 2(PC)
693-
RET
694-
MOVV s1_len+8(FP), R3
695-
ADDV R1, R3, R4
696-
loop:
697-
BNE R1, R4, 2(PC)
698-
RET
699-
MOVBU (R1), R6
700-
ADDV $1, R1
701-
MOVBU (R2), R7
702-
ADDV $1, R2
703-
BEQ R6, R7, loop
704-
MOVB R0, ret+32(FP)
705-
RET
706-
707682
// TODO: share code with memequal?
708683
TEXT bytes·Equal(SB),NOSPLIT,$0-49
709684
MOVV a_len+8(FP), R3

src/runtime/asm_mipsx.s

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -695,31 +695,6 @@ eq:
695695
MOVB R1, ret+8(FP)
696696
RET
697697

698-
// eqstring tests whether two strings are equal.
699-
// The compiler guarantees that strings passed
700-
// to eqstring have equal length.
701-
// See runtime_test.go:eqstring_generic for
702-
// equivalent Go code.
703-
TEXT runtime·eqstring(SB),NOSPLIT,$0-17
704-
MOVW s1_base+0(FP), R1
705-
MOVW s2_base+8(FP), R2
706-
MOVW $1, R3
707-
MOVBU R3, ret+16(FP)
708-
BNE R1, R2, 2(PC)
709-
RET
710-
MOVW s1_len+4(FP), R3
711-
ADDU R1, R3, R4
712-
loop:
713-
BNE R1, R4, 2(PC)
714-
RET
715-
MOVBU (R1), R6
716-
ADDU $1, R1
717-
MOVBU (R2), R7
718-
ADDU $1, R2
719-
BEQ R6, R7, loop
720-
MOVB R0, ret+16(FP)
721-
RET
722-
723698
TEXT bytes·Equal(SB),NOSPLIT,$0-25
724699
MOVW a_len+4(FP), R3
725700
MOVW b_len+16(FP), R4

src/runtime/asm_ppc64x.s

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,24 +1057,6 @@ equal:
10571057
MOVD $1, R9
10581058
RET
10591059

1060-
// eqstring tests whether two strings are equal.
1061-
// The compiler guarantees that strings passed
1062-
// to eqstring have equal length.
1063-
// See runtime_test.go:eqstring_generic for
1064-
// equivalent Go code.
1065-
TEXT runtime·eqstring(SB),NOSPLIT,$0-33
1066-
MOVD s1_base+0(FP), R3
1067-
MOVD s2_base+16(FP), R4
1068-
MOVD $1, R5
1069-
MOVB R5, ret+32(FP)
1070-
CMP R3, R4
1071-
BNE 2(PC)
1072-
RET
1073-
MOVD s1_len+8(FP), R5
1074-
BL runtime·memeqbody(SB)
1075-
MOVB R9, ret+32(FP)
1076-
RET
1077-
10781060
TEXT bytes·Equal(SB),NOSPLIT,$0-49
10791061
MOVD a_len+8(FP), R4
10801062
MOVD b_len+32(FP), R5

src/runtime/asm_s390x.s

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -704,18 +704,6 @@ TEXT runtime·memequal_varlen(SB),NOSPLIT|NOFRAME,$0-17
704704
LA ret+16(FP), R7
705705
BR runtime·memeqbody(SB)
706706

707-
// eqstring tests whether two strings are equal.
708-
// The compiler guarantees that strings passed
709-
// to eqstring have equal length.
710-
// See runtime_test.go:eqstring_generic for
711-
// equivalent Go code.
712-
TEXT runtime·eqstring(SB),NOSPLIT|NOFRAME,$0-33
713-
MOVD s1_base+0(FP), R3
714-
MOVD s1_len+8(FP), R6
715-
MOVD s2_base+16(FP), R5
716-
LA ret+32(FP), R7
717-
BR runtime·memeqbody(SB)
718-
719707
TEXT bytes·Equal(SB),NOSPLIT|NOFRAME,$0-49
720708
MOVD a_len+8(FP), R2
721709
MOVD b_len+32(FP), R6

src/runtime/runtime_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,9 @@ func eqstring_generic(s1, s2 string) bool {
196196
}
197197

198198
func TestEqString(t *testing.T) {
199-
// This isn't really an exhaustive test of eqstring, it's
199+
// This isn't really an exhaustive test of == on strings, it's
200200
// just a convenient way of documenting (via eqstring_generic)
201-
// what eqstring does.
201+
// what == does.
202202
s := []string{
203203
"",
204204
"a",
@@ -213,7 +213,7 @@ func TestEqString(t *testing.T) {
213213
x := s1 == s2
214214
y := eqstring_generic(s1, s2)
215215
if x != y {
216-
t.Errorf(`eqstring("%s","%s") = %t, want %t`, s1, s2, x, y)
216+
t.Errorf(`("%s" == "%s") = %t, want %t`, s1, s2, x, y)
217217
}
218218
}
219219
}

src/runtime/stubs.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,6 @@ func round(n, a uintptr) uintptr {
300300
func checkASM() bool
301301

302302
func memequal_varlen(a, b unsafe.Pointer) bool
303-
func eqstring(s1, s2 string) bool
304303

305304
// bool2int returns 0 if x is false or 1 if x is true.
306305
func bool2int(x bool) int {

0 commit comments

Comments
 (0)