1
0
mirror of https://github.com/golang/go synced 2024-11-19 13:54:56 -07:00

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 <moehrmann@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
Martin Möhrmann 2017-08-07 22:36:22 +02:00
parent d05a1238d6
commit 3216e0cefa
14 changed files with 200 additions and 377 deletions

View File

@ -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[:]
}

View File

@ -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

View File

@ -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]))
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])
// quick check of len before full compare for == or !=
// eqstring assumes that the lengths are equal
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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
//

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)
}
}
}

View File

@ -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 {