From 3216e0cefab43670c788a475237f6f4b235fc200 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Martin=20M=C3=B6hrmann?= Date: Mon, 7 Aug 2017 22:36:22 +0200 Subject: [PATCH] cmd/compile: replace eqstring with memequal MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall --- src/cmd/compile/internal/gc/builtin.go | 364 +++++++++--------- .../compile/internal/gc/builtin/runtime.go | 1 - src/cmd/compile/internal/gc/walk.go | 25 +- src/runtime/asm_386.s | 17 - src/runtime/asm_amd64.s | 17 - src/runtime/asm_amd64p32.s | 18 - src/runtime/asm_arm.s | 25 -- src/runtime/asm_arm64.s | 25 -- src/runtime/asm_mips64x.s | 25 -- src/runtime/asm_mipsx.s | 25 -- src/runtime/asm_ppc64x.s | 18 - src/runtime/asm_s390x.s | 12 - src/runtime/runtime_test.go | 6 +- src/runtime/stubs.go | 1 - 14 files changed, 201 insertions(+), 378 deletions(-) diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go index 05836cc951..fb3fdf90df 100644 --- a/src/cmd/compile/internal/gc/builtin.go +++ b/src/cmd/compile/internal/gc/builtin.go @@ -39,117 +39,116 @@ var runtimeDecls = [...]struct { {"concatstring5", funcTag, 29}, {"concatstrings", funcTag, 31}, {"cmpstring", funcTag, 33}, - {"eqstring", funcTag, 34}, - {"intstring", funcTag, 37}, - {"slicebytetostring", funcTag, 39}, - {"slicebytetostringtmp", funcTag, 40}, - {"slicerunetostring", funcTag, 43}, - {"stringtoslicebyte", funcTag, 44}, - {"stringtoslicerune", funcTag, 47}, - {"decoderune", funcTag, 48}, - {"slicecopy", funcTag, 50}, - {"slicestringcopy", funcTag, 51}, - {"convI2I", funcTag, 52}, - {"convT2E", funcTag, 53}, - {"convT2E16", funcTag, 53}, - {"convT2E32", funcTag, 53}, - {"convT2E64", funcTag, 53}, - {"convT2Estring", funcTag, 53}, - {"convT2Eslice", funcTag, 53}, - {"convT2Enoptr", funcTag, 53}, - {"convT2I", funcTag, 53}, - {"convT2I16", funcTag, 53}, - {"convT2I32", funcTag, 53}, - {"convT2I64", funcTag, 53}, - {"convT2Istring", funcTag, 53}, - {"convT2Islice", funcTag, 53}, - {"convT2Inoptr", funcTag, 53}, - {"assertE2I", funcTag, 52}, - {"assertE2I2", funcTag, 54}, - {"assertI2I", funcTag, 52}, - {"assertI2I2", funcTag, 54}, - {"panicdottypeE", funcTag, 55}, - {"panicdottypeI", funcTag, 55}, - {"panicnildottype", funcTag, 56}, - {"ifaceeq", funcTag, 59}, - {"efaceeq", funcTag, 59}, - {"makemap", funcTag, 61}, - {"mapaccess1", funcTag, 62}, - {"mapaccess1_fast32", funcTag, 63}, - {"mapaccess1_fast64", funcTag, 63}, - {"mapaccess1_faststr", funcTag, 63}, - {"mapaccess1_fat", funcTag, 64}, - {"mapaccess2", funcTag, 65}, - {"mapaccess2_fast32", funcTag, 66}, - {"mapaccess2_fast64", funcTag, 66}, - {"mapaccess2_faststr", funcTag, 66}, - {"mapaccess2_fat", funcTag, 67}, - {"mapassign", funcTag, 62}, - {"mapassign_fast32", funcTag, 63}, - {"mapassign_fast64", funcTag, 63}, - {"mapassign_faststr", funcTag, 63}, - {"mapiterinit", funcTag, 68}, - {"mapdelete", funcTag, 68}, - {"mapdelete_fast32", funcTag, 69}, - {"mapdelete_fast64", funcTag, 69}, - {"mapdelete_faststr", funcTag, 69}, - {"mapiternext", funcTag, 70}, - {"makechan64", funcTag, 72}, - {"makechan", funcTag, 73}, - {"chanrecv1", funcTag, 75}, - {"chanrecv2", funcTag, 76}, - {"chansend1", funcTag, 78}, + {"intstring", funcTag, 36}, + {"slicebytetostring", funcTag, 38}, + {"slicebytetostringtmp", funcTag, 39}, + {"slicerunetostring", funcTag, 42}, + {"stringtoslicebyte", funcTag, 43}, + {"stringtoslicerune", funcTag, 46}, + {"decoderune", funcTag, 47}, + {"slicecopy", funcTag, 49}, + {"slicestringcopy", funcTag, 50}, + {"convI2I", funcTag, 51}, + {"convT2E", funcTag, 52}, + {"convT2E16", funcTag, 52}, + {"convT2E32", funcTag, 52}, + {"convT2E64", funcTag, 52}, + {"convT2Estring", funcTag, 52}, + {"convT2Eslice", funcTag, 52}, + {"convT2Enoptr", funcTag, 52}, + {"convT2I", funcTag, 52}, + {"convT2I16", funcTag, 52}, + {"convT2I32", funcTag, 52}, + {"convT2I64", funcTag, 52}, + {"convT2Istring", funcTag, 52}, + {"convT2Islice", funcTag, 52}, + {"convT2Inoptr", funcTag, 52}, + {"assertE2I", funcTag, 51}, + {"assertE2I2", funcTag, 53}, + {"assertI2I", funcTag, 51}, + {"assertI2I2", funcTag, 53}, + {"panicdottypeE", funcTag, 54}, + {"panicdottypeI", funcTag, 54}, + {"panicnildottype", funcTag, 55}, + {"ifaceeq", funcTag, 58}, + {"efaceeq", funcTag, 58}, + {"makemap", funcTag, 60}, + {"mapaccess1", funcTag, 61}, + {"mapaccess1_fast32", funcTag, 62}, + {"mapaccess1_fast64", funcTag, 62}, + {"mapaccess1_faststr", funcTag, 62}, + {"mapaccess1_fat", funcTag, 63}, + {"mapaccess2", funcTag, 64}, + {"mapaccess2_fast32", funcTag, 65}, + {"mapaccess2_fast64", funcTag, 65}, + {"mapaccess2_faststr", funcTag, 65}, + {"mapaccess2_fat", funcTag, 66}, + {"mapassign", funcTag, 61}, + {"mapassign_fast32", funcTag, 62}, + {"mapassign_fast64", funcTag, 62}, + {"mapassign_faststr", funcTag, 62}, + {"mapiterinit", funcTag, 67}, + {"mapdelete", funcTag, 67}, + {"mapdelete_fast32", funcTag, 68}, + {"mapdelete_fast64", funcTag, 68}, + {"mapdelete_faststr", funcTag, 68}, + {"mapiternext", funcTag, 69}, + {"makechan64", funcTag, 71}, + {"makechan", funcTag, 72}, + {"chanrecv1", funcTag, 74}, + {"chanrecv2", funcTag, 75}, + {"chansend1", funcTag, 77}, {"closechan", funcTag, 23}, - {"writeBarrier", varTag, 80}, - {"writebarrierptr", funcTag, 81}, - {"typedmemmove", funcTag, 82}, - {"typedmemclr", funcTag, 83}, - {"typedslicecopy", funcTag, 84}, - {"selectnbsend", funcTag, 85}, - {"selectnbrecv", funcTag, 86}, - {"selectnbrecv2", funcTag, 88}, - {"newselect", funcTag, 89}, - {"selectsend", funcTag, 90}, - {"selectrecv", funcTag, 91}, - {"selectdefault", funcTag, 56}, - {"selectgo", funcTag, 92}, + {"writeBarrier", varTag, 79}, + {"writebarrierptr", funcTag, 80}, + {"typedmemmove", funcTag, 81}, + {"typedmemclr", funcTag, 82}, + {"typedslicecopy", funcTag, 83}, + {"selectnbsend", funcTag, 84}, + {"selectnbrecv", funcTag, 85}, + {"selectnbrecv2", funcTag, 87}, + {"newselect", funcTag, 88}, + {"selectsend", funcTag, 89}, + {"selectrecv", funcTag, 90}, + {"selectdefault", funcTag, 55}, + {"selectgo", funcTag, 91}, {"block", funcTag, 5}, - {"makeslice", funcTag, 94}, - {"makeslice64", funcTag, 95}, - {"growslice", funcTag, 96}, - {"memmove", funcTag, 97}, - {"memclrNoHeapPointers", funcTag, 98}, - {"memclrHasPointers", funcTag, 98}, - {"memequal", funcTag, 99}, - {"memequal8", funcTag, 100}, - {"memequal16", funcTag, 100}, - {"memequal32", funcTag, 100}, - {"memequal64", funcTag, 100}, - {"memequal128", funcTag, 100}, - {"int64div", funcTag, 101}, - {"uint64div", funcTag, 102}, - {"int64mod", funcTag, 101}, - {"uint64mod", funcTag, 102}, - {"float64toint64", funcTag, 103}, - {"float64touint64", funcTag, 104}, - {"float64touint32", funcTag, 106}, - {"int64tofloat64", funcTag, 107}, - {"uint64tofloat64", funcTag, 108}, - {"uint32tofloat64", funcTag, 109}, - {"complex128div", funcTag, 110}, - {"racefuncenter", funcTag, 111}, + {"makeslice", funcTag, 93}, + {"makeslice64", funcTag, 94}, + {"growslice", funcTag, 95}, + {"memmove", funcTag, 96}, + {"memclrNoHeapPointers", funcTag, 97}, + {"memclrHasPointers", funcTag, 97}, + {"memequal", funcTag, 98}, + {"memequal8", funcTag, 99}, + {"memequal16", funcTag, 99}, + {"memequal32", funcTag, 99}, + {"memequal64", funcTag, 99}, + {"memequal128", funcTag, 99}, + {"int64div", funcTag, 100}, + {"uint64div", funcTag, 101}, + {"int64mod", funcTag, 100}, + {"uint64mod", funcTag, 101}, + {"float64toint64", funcTag, 102}, + {"float64touint64", funcTag, 103}, + {"float64touint32", funcTag, 105}, + {"int64tofloat64", funcTag, 106}, + {"uint64tofloat64", funcTag, 107}, + {"uint32tofloat64", funcTag, 108}, + {"complex128div", funcTag, 109}, + {"racefuncenter", funcTag, 110}, {"racefuncexit", funcTag, 5}, - {"raceread", funcTag, 111}, - {"racewrite", funcTag, 111}, - {"racereadrange", funcTag, 112}, - {"racewriterange", funcTag, 112}, - {"msanread", funcTag, 112}, - {"msanwrite", funcTag, 112}, + {"raceread", funcTag, 110}, + {"racewrite", funcTag, 110}, + {"racereadrange", funcTag, 111}, + {"racewriterange", funcTag, 111}, + {"msanread", funcTag, 111}, + {"msanwrite", funcTag, 111}, {"support_popcnt", varTag, 11}, } func runtimeTypes() []*types.Type { - var typs [113]*types.Type + var typs [112]*types.Type typs[0] = types.Bytetype typs[1] = types.NewPtr(typs[0]) typs[2] = types.Types[TANY] @@ -184,84 +183,83 @@ func runtimeTypes() []*types.Type { typs[31] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[30])}, []*Node{anonfield(typs[21])}) typs[32] = types.Types[TINT] typs[33] = functype(nil, []*Node{anonfield(typs[21]), anonfield(typs[21])}, []*Node{anonfield(typs[32])}) - typs[34] = functype(nil, []*Node{anonfield(typs[21]), anonfield(typs[21])}, []*Node{anonfield(typs[11])}) - typs[35] = types.NewArray(typs[0], 4) - typs[36] = types.NewPtr(typs[35]) - typs[37] = functype(nil, []*Node{anonfield(typs[36]), anonfield(typs[15])}, []*Node{anonfield(typs[21])}) - typs[38] = types.NewSlice(typs[0]) - typs[39] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[38])}, []*Node{anonfield(typs[21])}) - typs[40] = functype(nil, []*Node{anonfield(typs[38])}, []*Node{anonfield(typs[21])}) - typs[41] = types.Runetype - typs[42] = types.NewSlice(typs[41]) - typs[43] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[42])}, []*Node{anonfield(typs[21])}) - typs[44] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[21])}, []*Node{anonfield(typs[38])}) - typs[45] = types.NewArray(typs[41], 32) - typs[46] = types.NewPtr(typs[45]) - typs[47] = functype(nil, []*Node{anonfield(typs[46]), anonfield(typs[21])}, []*Node{anonfield(typs[42])}) - typs[48] = functype(nil, []*Node{anonfield(typs[21]), anonfield(typs[32])}, []*Node{anonfield(typs[41]), anonfield(typs[32])}) - typs[49] = types.Types[TUINTPTR] - typs[50] = functype(nil, []*Node{anonfield(typs[2]), anonfield(typs[2]), anonfield(typs[49])}, []*Node{anonfield(typs[32])}) - typs[51] = functype(nil, []*Node{anonfield(typs[2]), anonfield(typs[2])}, []*Node{anonfield(typs[32])}) - typs[52] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])}) - typs[53] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])}) - typs[54] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[11])}) - typs[55] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil) - typs[56] = functype(nil, []*Node{anonfield(typs[1])}, nil) - typs[57] = types.NewPtr(typs[49]) - typs[58] = types.Types[TUNSAFEPTR] - typs[59] = functype(nil, []*Node{anonfield(typs[57]), anonfield(typs[58]), anonfield(typs[58])}, []*Node{anonfield(typs[11])}) - typs[60] = types.NewMap(typs[2], typs[2]) - typs[61] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*Node{anonfield(typs[60])}) - typs[62] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[60]), anonfield(typs[3])}, []*Node{anonfield(typs[3])}) - typs[63] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[60]), anonfield(typs[2])}, []*Node{anonfield(typs[3])}) - typs[64] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[60]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])}) - typs[65] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[60]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[11])}) - typs[66] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[60]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[11])}) - typs[67] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[60]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[11])}) - typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[60]), anonfield(typs[3])}, nil) - typs[69] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[60]), anonfield(typs[2])}, nil) - typs[70] = functype(nil, []*Node{anonfield(typs[3])}, nil) - typs[71] = types.NewChan(typs[2], types.Cboth) - typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[71])}) - typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32])}, []*Node{anonfield(typs[71])}) - typs[74] = types.NewChan(typs[2], types.Crecv) - typs[75] = functype(nil, []*Node{anonfield(typs[74]), anonfield(typs[3])}, nil) - typs[76] = functype(nil, []*Node{anonfield(typs[74]), anonfield(typs[3])}, []*Node{anonfield(typs[11])}) - typs[77] = types.NewChan(typs[2], types.Csend) - typs[78] = functype(nil, []*Node{anonfield(typs[77]), anonfield(typs[3])}, nil) - typs[79] = types.NewArray(typs[0], 3) - typs[80] = tostruct([]*Node{namedfield("enabled", typs[11]), namedfield("pad", typs[79]), namedfield("needed", typs[11]), namedfield("cgo", typs[11]), namedfield("alignme", typs[17])}) - typs[81] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[2])}, nil) - typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil) - typs[83] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil) - typs[84] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2]), anonfield(typs[2])}, []*Node{anonfield(typs[32])}) - typs[85] = functype(nil, []*Node{anonfield(typs[77]), anonfield(typs[3])}, []*Node{anonfield(typs[11])}) - typs[86] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[74])}, []*Node{anonfield(typs[11])}) - typs[87] = types.NewPtr(typs[11]) - typs[88] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[87]), anonfield(typs[74])}, []*Node{anonfield(typs[11])}) - typs[89] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[8])}, nil) - typs[90] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[77]), anonfield(typs[3])}, nil) - typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[74]), anonfield(typs[3]), anonfield(typs[87])}, nil) - typs[92] = functype(nil, []*Node{anonfield(typs[1])}, []*Node{anonfield(typs[32])}) - typs[93] = types.NewSlice(typs[2]) - typs[94] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32]), anonfield(typs[32])}, []*Node{anonfield(typs[93])}) - typs[95] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[93])}) - typs[96] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[93]), anonfield(typs[32])}, []*Node{anonfield(typs[93])}) - typs[97] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[49])}, nil) - typs[98] = functype(nil, []*Node{anonfield(typs[58]), anonfield(typs[49])}, nil) - typs[99] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[49])}, []*Node{anonfield(typs[11])}) - typs[100] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[11])}) - typs[101] = functype(nil, []*Node{anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[15])}) - typs[102] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[17])}, []*Node{anonfield(typs[17])}) - typs[103] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[15])}) - typs[104] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[17])}) - typs[105] = types.Types[TUINT32] - typs[106] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[105])}) - typs[107] = functype(nil, []*Node{anonfield(typs[15])}, []*Node{anonfield(typs[13])}) - typs[108] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[13])}) - typs[109] = functype(nil, []*Node{anonfield(typs[105])}, []*Node{anonfield(typs[13])}) - typs[110] = functype(nil, []*Node{anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[19])}) - typs[111] = functype(nil, []*Node{anonfield(typs[49])}, nil) - typs[112] = functype(nil, []*Node{anonfield(typs[49]), anonfield(typs[49])}, nil) + typs[34] = types.NewArray(typs[0], 4) + typs[35] = types.NewPtr(typs[34]) + typs[36] = functype(nil, []*Node{anonfield(typs[35]), anonfield(typs[15])}, []*Node{anonfield(typs[21])}) + typs[37] = types.NewSlice(typs[0]) + typs[38] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[37])}, []*Node{anonfield(typs[21])}) + typs[39] = functype(nil, []*Node{anonfield(typs[37])}, []*Node{anonfield(typs[21])}) + typs[40] = types.Runetype + typs[41] = types.NewSlice(typs[40]) + typs[42] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[41])}, []*Node{anonfield(typs[21])}) + typs[43] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[21])}, []*Node{anonfield(typs[37])}) + typs[44] = types.NewArray(typs[40], 32) + typs[45] = types.NewPtr(typs[44]) + typs[46] = functype(nil, []*Node{anonfield(typs[45]), anonfield(typs[21])}, []*Node{anonfield(typs[41])}) + typs[47] = functype(nil, []*Node{anonfield(typs[21]), anonfield(typs[32])}, []*Node{anonfield(typs[40]), anonfield(typs[32])}) + typs[48] = types.Types[TUINTPTR] + typs[49] = functype(nil, []*Node{anonfield(typs[2]), anonfield(typs[2]), anonfield(typs[48])}, []*Node{anonfield(typs[32])}) + typs[50] = functype(nil, []*Node{anonfield(typs[2]), anonfield(typs[2])}, []*Node{anonfield(typs[32])}) + typs[51] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])}) + typs[52] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])}) + typs[53] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[11])}) + typs[54] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil) + typs[55] = functype(nil, []*Node{anonfield(typs[1])}, nil) + typs[56] = types.NewPtr(typs[48]) + typs[57] = types.Types[TUNSAFEPTR] + typs[58] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[57]), anonfield(typs[57])}, []*Node{anonfield(typs[11])}) + typs[59] = types.NewMap(typs[2], typs[2]) + typs[60] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*Node{anonfield(typs[59])}) + typs[61] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[59]), anonfield(typs[3])}, []*Node{anonfield(typs[3])}) + typs[62] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[59]), anonfield(typs[2])}, []*Node{anonfield(typs[3])}) + typs[63] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[59]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])}) + typs[64] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[59]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[11])}) + typs[65] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[59]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[11])}) + typs[66] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[59]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[11])}) + typs[67] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[59]), anonfield(typs[3])}, nil) + typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[59]), anonfield(typs[2])}, nil) + typs[69] = functype(nil, []*Node{anonfield(typs[3])}, nil) + typs[70] = types.NewChan(typs[2], types.Cboth) + typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[70])}) + typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32])}, []*Node{anonfield(typs[70])}) + typs[73] = types.NewChan(typs[2], types.Crecv) + typs[74] = functype(nil, []*Node{anonfield(typs[73]), anonfield(typs[3])}, nil) + typs[75] = functype(nil, []*Node{anonfield(typs[73]), anonfield(typs[3])}, []*Node{anonfield(typs[11])}) + typs[76] = types.NewChan(typs[2], types.Csend) + typs[77] = functype(nil, []*Node{anonfield(typs[76]), anonfield(typs[3])}, nil) + typs[78] = types.NewArray(typs[0], 3) + typs[79] = tostruct([]*Node{namedfield("enabled", typs[11]), namedfield("pad", typs[78]), namedfield("needed", typs[11]), namedfield("cgo", typs[11]), namedfield("alignme", typs[17])}) + typs[80] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[2])}, nil) + typs[81] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil) + typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil) + typs[83] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2]), anonfield(typs[2])}, []*Node{anonfield(typs[32])}) + typs[84] = functype(nil, []*Node{anonfield(typs[76]), anonfield(typs[3])}, []*Node{anonfield(typs[11])}) + typs[85] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[73])}, []*Node{anonfield(typs[11])}) + typs[86] = types.NewPtr(typs[11]) + typs[87] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[86]), anonfield(typs[73])}, []*Node{anonfield(typs[11])}) + typs[88] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[8])}, nil) + typs[89] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[76]), anonfield(typs[3])}, nil) + typs[90] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[73]), anonfield(typs[3]), anonfield(typs[86])}, nil) + typs[91] = functype(nil, []*Node{anonfield(typs[1])}, []*Node{anonfield(typs[32])}) + typs[92] = types.NewSlice(typs[2]) + typs[93] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32]), anonfield(typs[32])}, []*Node{anonfield(typs[92])}) + typs[94] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[92])}) + typs[95] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[92]), anonfield(typs[32])}, []*Node{anonfield(typs[92])}) + typs[96] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[48])}, nil) + typs[97] = functype(nil, []*Node{anonfield(typs[57]), anonfield(typs[48])}, nil) + typs[98] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[48])}, []*Node{anonfield(typs[11])}) + typs[99] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[11])}) + typs[100] = functype(nil, []*Node{anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[15])}) + typs[101] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[17])}, []*Node{anonfield(typs[17])}) + typs[102] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[15])}) + typs[103] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[17])}) + typs[104] = types.Types[TUINT32] + typs[105] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[104])}) + typs[106] = functype(nil, []*Node{anonfield(typs[15])}, []*Node{anonfield(typs[13])}) + typs[107] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[13])}) + typs[108] = functype(nil, []*Node{anonfield(typs[104])}, []*Node{anonfield(typs[13])}) + typs[109] = functype(nil, []*Node{anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[19])}) + typs[110] = functype(nil, []*Node{anonfield(typs[48])}, nil) + typs[111] = functype(nil, []*Node{anonfield(typs[48]), anonfield(typs[48])}, nil) return typs[:] } diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go index f69459c549..6313b1a44c 100644 --- a/src/cmd/compile/internal/gc/builtin/runtime.go +++ b/src/cmd/compile/internal/gc/builtin/runtime.go @@ -48,7 +48,6 @@ func concatstring5(*[32]byte, string, string, string, string, string) string func concatstrings(*[32]byte, []string) string func cmpstring(string, string) int -func eqstring(string, string) bool func intstring(*[4]byte, int64) string func slicebytetostring(*[32]byte, []byte) string func slicebytetostringtmp([]byte) string diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index dea5893bea..3ed4bc3edd 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -1369,18 +1369,27 @@ opswitch: n.Left = cheapexpr(n.Left, init) n.Right = cheapexpr(n.Right, init) - r = mkcall("eqstring", types.Types[TBOOL], init, conv(n.Left, types.Types[TSTRING]), conv(n.Right, types.Types[TSTRING])) - - // quick check of len before full compare for == or != - // eqstring assumes that the lengths are equal + lstr := conv(n.Left, types.Types[TSTRING]) + rstr := conv(n.Right, types.Types[TSTRING]) + lptr := nod(OSPTR, lstr, nil) + rptr := nod(OSPTR, rstr, nil) + llen := conv(nod(OLEN, lstr, nil), types.Types[TUINTPTR]) + rlen := conv(nod(OLEN, rstr, nil), types.Types[TUINTPTR]) + + fn := syslook("memequal") + fn = substArgTypes(fn, types.Types[TUINT8], types.Types[TUINT8]) + r = mkcall1(fn, types.Types[TBOOL], init, lptr, rptr, llen) + + // quick check of len before full compare for == or !=. + // memequal then tests equality up to length len. // TODO(marvin): Fix Node.EType type union. if Op(n.Etype) == OEQ { - // len(left) == len(right) && eqstring(left, right) - r = nod(OANDAND, nod(OEQ, nod(OLEN, n.Left, nil), nod(OLEN, n.Right, nil)), r) + // len(left) == len(right) && memequal(left, right, len) + r = nod(OANDAND, nod(OEQ, llen, rlen), r) } else { - // len(left) != len(right) || !eqstring(left, right) + // len(left) != len(right) || !memequal(left, right, len) r = nod(ONOT, r, nil) - r = nod(OOROR, nod(ONE, nod(OLEN, n.Left, nil), nod(OLEN, n.Right, nil)), r) + r = nod(OOROR, nod(ONE, llen, rlen), r) } r = typecheck(r, Erv) diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index e1c3267153..76758686e5 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -1306,23 +1306,6 @@ eq: MOVB $1, ret+8(FP) RET -// eqstring tests whether two strings are equal. -// The compiler guarantees that strings passed -// to eqstring have equal length. -// See runtime_test.go:eqstring_generic for -// equivalent Go code. -TEXT runtime·eqstring(SB),NOSPLIT,$0-17 - MOVL s1_base+0(FP), SI - MOVL s2_base+8(FP), DI - CMPL SI, DI - JEQ same - MOVL s1_len+4(FP), BX - LEAL ret+16(FP), AX - JMP runtime·memeqbody(SB) -same: - MOVB $1, ret+16(FP) - RET - TEXT bytes·Equal(SB),NOSPLIT,$0-25 MOVL a_len+4(FP), BX MOVL b_len+16(FP), CX diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index dfa49de544..f992276794 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -1326,23 +1326,6 @@ eq: MOVB $1, ret+16(FP) RET -// eqstring tests whether two strings are equal. -// The compiler guarantees that strings passed -// to eqstring have equal length. -// See runtime_test.go:eqstring_generic for -// equivalent Go code. -TEXT runtime·eqstring(SB),NOSPLIT,$0-33 - MOVQ s1_base+0(FP), SI - MOVQ s2_base+16(FP), DI - CMPQ SI, DI - JEQ eq - MOVQ s1_len+8(FP), BX - LEAQ ret+32(FP), AX - JMP runtime·memeqbody(SB) -eq: - MOVB $1, ret+32(FP) - RET - // a in SI // b in DI // count in BX diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s index 1f70ab87f1..f9417196c5 100644 --- a/src/runtime/asm_amd64p32.s +++ b/src/runtime/asm_amd64p32.s @@ -641,24 +641,6 @@ eq: MOVB $1, ret+8(FP) RET -// eqstring tests whether two strings are equal. -// The compiler guarantees that strings passed -// to eqstring have equal length. -// See runtime_test.go:eqstring_generic for -// equivalent Go code. -TEXT runtime·eqstring(SB),NOSPLIT,$0-17 - MOVL s1_base+0(FP), SI - MOVL s2_base+8(FP), DI - CMPL SI, DI - JEQ same - MOVL s1_len+4(FP), BX - CALL runtime·memeqbody(SB) - MOVB AX, ret+16(FP) - RET -same: - MOVB $1, ret+16(FP) - RET - // a in SI // b in DI // count in BX diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index 74761d4450..79c5d43ec7 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -813,31 +813,6 @@ samebytes: MOVW R0, (R7) RET -// eqstring tests whether two strings are equal. -// The compiler guarantees that strings passed -// to eqstring have equal length. -// See runtime_test.go:eqstring_generic for -// equivalent Go code. -TEXT runtime·eqstring(SB),NOSPLIT,$-4-17 - MOVW s1_base+0(FP), R2 - MOVW s2_base+8(FP), R3 - MOVW $1, R8 - MOVB R8, ret+16(FP) - CMP R2, R3 - RET.EQ - MOVW s1_len+4(FP), R0 - ADD R2, R0, R6 -loop: - CMP R2, R6 - RET.EQ - MOVBU.P 1(R2), R4 - MOVBU.P 1(R3), R5 - CMP R4, R5 - BEQ loop - MOVW $0, R8 - MOVB R8, ret+16(FP) - RET - // TODO: share code with memequal? TEXT bytes·Equal(SB),NOSPLIT,$0-25 MOVW a_len+4(FP), R1 diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s index 32c06d5c37..4a68b4ab23 100644 --- a/src/runtime/asm_arm64.s +++ b/src/runtime/asm_arm64.s @@ -806,31 +806,6 @@ samebytes: MOVD R4, (R7) RET -// eqstring tests whether two strings are equal. -// The compiler guarantees that strings passed -// to eqstring have equal length. -// See runtime_test.go:eqstring_generic for -// equivalent Go code. -TEXT runtime·eqstring(SB),NOSPLIT,$0-33 - MOVD s1_base+0(FP), R0 - MOVD s1_len+8(FP), R1 - MOVD s2_base+16(FP), R2 - ADD R0, R1 // end -loop: - CMP R0, R1 - BEQ equal // reaches the end - MOVBU.P 1(R0), R4 - MOVBU.P 1(R2), R5 - CMP R4, R5 - BEQ loop -notequal: - MOVB ZR, ret+32(FP) - RET -equal: - MOVD $1, R0 - MOVB R0, ret+32(FP) - RET - // // functions for other packages // diff --git a/src/runtime/asm_mips64x.s b/src/runtime/asm_mips64x.s index 58ee58ed5b..338f6d4487 100644 --- a/src/runtime/asm_mips64x.s +++ b/src/runtime/asm_mips64x.s @@ -679,31 +679,6 @@ eq: MOVB R1, ret+16(FP) RET -// eqstring tests whether two strings are equal. -// The compiler guarantees that strings passed -// to eqstring have equal length. -// See runtime_test.go:eqstring_generic for -// equivalent Go code. -TEXT runtime·eqstring(SB),NOSPLIT,$0-33 - MOVV s1_base+0(FP), R1 - MOVV s2_base+16(FP), R2 - MOVV $1, R3 - MOVB R3, ret+32(FP) - BNE R1, R2, 2(PC) - RET - MOVV s1_len+8(FP), R3 - ADDV R1, R3, R4 -loop: - BNE R1, R4, 2(PC) - RET - MOVBU (R1), R6 - ADDV $1, R1 - MOVBU (R2), R7 - ADDV $1, R2 - BEQ R6, R7, loop - MOVB R0, ret+32(FP) - RET - // TODO: share code with memequal? TEXT bytes·Equal(SB),NOSPLIT,$0-49 MOVV a_len+8(FP), R3 diff --git a/src/runtime/asm_mipsx.s b/src/runtime/asm_mipsx.s index 7a365419b0..476e207bf9 100644 --- a/src/runtime/asm_mipsx.s +++ b/src/runtime/asm_mipsx.s @@ -695,31 +695,6 @@ eq: MOVB R1, ret+8(FP) RET -// eqstring tests whether two strings are equal. -// The compiler guarantees that strings passed -// to eqstring have equal length. -// See runtime_test.go:eqstring_generic for -// equivalent Go code. -TEXT runtime·eqstring(SB),NOSPLIT,$0-17 - MOVW s1_base+0(FP), R1 - MOVW s2_base+8(FP), R2 - MOVW $1, R3 - MOVBU R3, ret+16(FP) - BNE R1, R2, 2(PC) - RET - MOVW s1_len+4(FP), R3 - ADDU R1, R3, R4 -loop: - BNE R1, R4, 2(PC) - RET - MOVBU (R1), R6 - ADDU $1, R1 - MOVBU (R2), R7 - ADDU $1, R2 - BEQ R6, R7, loop - MOVB R0, ret+16(FP) - RET - TEXT bytes·Equal(SB),NOSPLIT,$0-25 MOVW a_len+4(FP), R3 MOVW b_len+16(FP), R4 diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s index 142ecdb2b1..0251689b37 100644 --- a/src/runtime/asm_ppc64x.s +++ b/src/runtime/asm_ppc64x.s @@ -1057,24 +1057,6 @@ equal: MOVD $1, R9 RET -// eqstring tests whether two strings are equal. -// The compiler guarantees that strings passed -// to eqstring have equal length. -// See runtime_test.go:eqstring_generic for -// equivalent Go code. -TEXT runtime·eqstring(SB),NOSPLIT,$0-33 - MOVD s1_base+0(FP), R3 - MOVD s2_base+16(FP), R4 - MOVD $1, R5 - MOVB R5, ret+32(FP) - CMP R3, R4 - BNE 2(PC) - RET - MOVD s1_len+8(FP), R5 - BL runtime·memeqbody(SB) - MOVB R9, ret+32(FP) - RET - TEXT bytes·Equal(SB),NOSPLIT,$0-49 MOVD a_len+8(FP), R4 MOVD b_len+32(FP), R5 diff --git a/src/runtime/asm_s390x.s b/src/runtime/asm_s390x.s index 757627d1ea..bde4f0e5d9 100644 --- a/src/runtime/asm_s390x.s +++ b/src/runtime/asm_s390x.s @@ -704,18 +704,6 @@ TEXT runtime·memequal_varlen(SB),NOSPLIT|NOFRAME,$0-17 LA ret+16(FP), R7 BR runtime·memeqbody(SB) -// eqstring tests whether two strings are equal. -// The compiler guarantees that strings passed -// to eqstring have equal length. -// See runtime_test.go:eqstring_generic for -// equivalent Go code. -TEXT runtime·eqstring(SB),NOSPLIT|NOFRAME,$0-33 - MOVD s1_base+0(FP), R3 - MOVD s1_len+8(FP), R6 - MOVD s2_base+16(FP), R5 - LA ret+32(FP), R7 - BR runtime·memeqbody(SB) - TEXT bytes·Equal(SB),NOSPLIT|NOFRAME,$0-49 MOVD a_len+8(FP), R2 MOVD b_len+32(FP), R6 diff --git a/src/runtime/runtime_test.go b/src/runtime/runtime_test.go index e9bc256712..922cd830bc 100644 --- a/src/runtime/runtime_test.go +++ b/src/runtime/runtime_test.go @@ -196,9 +196,9 @@ func eqstring_generic(s1, s2 string) bool { } func TestEqString(t *testing.T) { - // This isn't really an exhaustive test of eqstring, it's + // This isn't really an exhaustive test of == on strings, it's // just a convenient way of documenting (via eqstring_generic) - // what eqstring does. + // what == does. s := []string{ "", "a", @@ -213,7 +213,7 @@ func TestEqString(t *testing.T) { x := s1 == s2 y := eqstring_generic(s1, s2) if x != y { - t.Errorf(`eqstring("%s","%s") = %t, want %t`, s1, s2, x, y) + t.Errorf(`("%s" == "%s") = %t, want %t`, s1, s2, x, y) } } } diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index 1af704cb24..19cddc9f65 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -300,7 +300,6 @@ func round(n, a uintptr) uintptr { func checkASM() bool func memequal_varlen(a, b unsafe.Pointer) bool -func eqstring(s1, s2 string) bool // bool2int returns 0 if x is false or 1 if x is true. func bool2int(x bool) int { -- 2.48.1