From b679665a182bd6ec2989ae759df6b11142921cfb Mon Sep 17 00:00:00 2001 From: =?utf8?q?Martin=20Mo=CC=88hrmann?= Date: Thu, 27 Oct 2016 23:31:38 +0200 Subject: [PATCH] cmd/compile: move stringtoslicebytetmp to the backend MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit - removes the runtime function stringtoslicebytetmp - removes the generation of calls to stringtoslicebytetmp from the frontend - adds handling of OSTRARRAYBYTETMP in the backend This reduces binary sizes and avoids function call overhead. Change-Id: Ib9988d48549cee663b685b4897a483f94727b940 Reviewed-on: https://go-review.googlesource.com/32158 Reviewed-by: Brad Fitzpatrick Reviewed-by: Matthew Dempsky Reviewed-by: Josh Bleecher Snyder Run-TryBot: Martin Möhrmann TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/builtin.go | 294 +++++++++--------- .../compile/internal/gc/builtin/runtime.go | 1 - src/cmd/compile/internal/gc/racewalk.go | 4 + src/cmd/compile/internal/gc/ssa.go | 5 + src/cmd/compile/internal/gc/walk.go | 10 +- src/runtime/string.go | 12 - test/range.go | 25 ++ 7 files changed, 188 insertions(+), 163 deletions(-) diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go index 56df7d00c8..167e659016 100644 --- a/src/cmd/compile/internal/gc/builtin.go +++ b/src/cmd/compile/internal/gc/builtin.go @@ -42,97 +42,96 @@ var runtimeDecls = [...]struct { {"slicebytetostringtmp", funcTag, 41}, {"slicerunetostring", funcTag, 44}, {"stringtoslicebyte", funcTag, 45}, - {"stringtoslicebytetmp", funcTag, 46}, - {"stringtoslicerune", funcTag, 49}, - {"decoderune", funcTag, 50}, - {"slicecopy", funcTag, 52}, - {"slicestringcopy", funcTag, 53}, - {"convI2I", funcTag, 54}, - {"convT2E", funcTag, 55}, - {"convT2I", funcTag, 55}, - {"assertE2E", funcTag, 56}, - {"assertE2E2", funcTag, 57}, - {"assertE2I", funcTag, 56}, - {"assertE2I2", funcTag, 57}, - {"assertE2T", funcTag, 56}, - {"assertE2T2", funcTag, 57}, - {"assertI2E", funcTag, 56}, - {"assertI2E2", funcTag, 57}, - {"assertI2I", funcTag, 56}, - {"assertI2I2", funcTag, 57}, - {"assertI2T", funcTag, 56}, - {"assertI2T2", funcTag, 57}, - {"panicdottype", funcTag, 58}, - {"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}, - {"mapiterinit", funcTag, 68}, - {"mapdelete", funcTag, 68}, - {"mapiternext", funcTag, 69}, - {"makechan", funcTag, 71}, - {"chanrecv1", funcTag, 73}, - {"chanrecv2", funcTag, 74}, - {"chansend1", funcTag, 76}, + {"stringtoslicerune", funcTag, 48}, + {"decoderune", funcTag, 49}, + {"slicecopy", funcTag, 51}, + {"slicestringcopy", funcTag, 52}, + {"convI2I", funcTag, 53}, + {"convT2E", funcTag, 54}, + {"convT2I", funcTag, 54}, + {"assertE2E", funcTag, 55}, + {"assertE2E2", funcTag, 56}, + {"assertE2I", funcTag, 55}, + {"assertE2I2", funcTag, 56}, + {"assertE2T", funcTag, 55}, + {"assertE2T2", funcTag, 56}, + {"assertI2E", funcTag, 55}, + {"assertI2E2", funcTag, 56}, + {"assertI2I", funcTag, 55}, + {"assertI2I2", funcTag, 56}, + {"assertI2T", funcTag, 55}, + {"assertI2T2", funcTag, 56}, + {"panicdottype", funcTag, 57}, + {"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}, + {"mapiterinit", funcTag, 67}, + {"mapdelete", funcTag, 67}, + {"mapiternext", funcTag, 68}, + {"makechan", funcTag, 70}, + {"chanrecv1", funcTag, 72}, + {"chanrecv2", funcTag, 73}, + {"chansend1", funcTag, 75}, {"closechan", funcTag, 24}, - {"writeBarrier", varTag, 77}, - {"writebarrierptr", funcTag, 78}, - {"typedmemmove", funcTag, 79}, - {"typedslicecopy", funcTag, 80}, - {"selectnbsend", funcTag, 81}, - {"selectnbrecv", funcTag, 82}, - {"selectnbrecv2", funcTag, 84}, - {"newselect", funcTag, 85}, - {"selectsend", funcTag, 81}, - {"selectrecv", funcTag, 74}, - {"selectrecv2", funcTag, 86}, - {"selectdefault", funcTag, 87}, - {"selectgo", funcTag, 88}, + {"writeBarrier", varTag, 76}, + {"writebarrierptr", funcTag, 77}, + {"typedmemmove", funcTag, 78}, + {"typedslicecopy", funcTag, 79}, + {"selectnbsend", funcTag, 80}, + {"selectnbrecv", funcTag, 81}, + {"selectnbrecv2", funcTag, 83}, + {"newselect", funcTag, 84}, + {"selectsend", funcTag, 80}, + {"selectrecv", funcTag, 73}, + {"selectrecv2", funcTag, 85}, + {"selectdefault", funcTag, 86}, + {"selectgo", funcTag, 87}, {"block", funcTag, 5}, - {"makeslice", funcTag, 90}, - {"makeslice64", funcTag, 91}, - {"growslice", funcTag, 92}, - {"memmove", funcTag, 93}, - {"memclr", funcTag, 94}, - {"memequal", funcTag, 95}, - {"memequal8", funcTag, 96}, - {"memequal16", funcTag, 96}, - {"memequal32", funcTag, 96}, - {"memequal64", funcTag, 96}, - {"memequal128", funcTag, 96}, - {"int64div", funcTag, 97}, - {"uint64div", funcTag, 98}, - {"int64mod", funcTag, 97}, - {"uint64mod", funcTag, 98}, - {"float64toint64", funcTag, 99}, - {"float64touint64", funcTag, 100}, - {"float64touint32", funcTag, 102}, - {"int64tofloat64", funcTag, 103}, - {"uint64tofloat64", funcTag, 104}, - {"uint32tofloat64", funcTag, 105}, - {"complex128div", funcTag, 106}, - {"racefuncenter", funcTag, 107}, + {"makeslice", funcTag, 89}, + {"makeslice64", funcTag, 90}, + {"growslice", funcTag, 91}, + {"memmove", funcTag, 92}, + {"memclr", funcTag, 93}, + {"memequal", funcTag, 94}, + {"memequal8", funcTag, 95}, + {"memequal16", funcTag, 95}, + {"memequal32", funcTag, 95}, + {"memequal64", funcTag, 95}, + {"memequal128", funcTag, 95}, + {"int64div", funcTag, 96}, + {"uint64div", funcTag, 97}, + {"int64mod", funcTag, 96}, + {"uint64mod", funcTag, 97}, + {"float64toint64", funcTag, 98}, + {"float64touint64", funcTag, 99}, + {"float64touint32", funcTag, 101}, + {"int64tofloat64", funcTag, 102}, + {"uint64tofloat64", funcTag, 103}, + {"uint32tofloat64", funcTag, 104}, + {"complex128div", funcTag, 105}, + {"racefuncenter", funcTag, 106}, {"racefuncexit", funcTag, 5}, - {"raceread", funcTag, 107}, - {"racewrite", funcTag, 107}, - {"racereadrange", funcTag, 108}, - {"racewriterange", funcTag, 108}, - {"msanread", funcTag, 108}, - {"msanwrite", funcTag, 108}, + {"raceread", funcTag, 106}, + {"racewrite", funcTag, 106}, + {"racereadrange", funcTag, 107}, + {"racewriterange", funcTag, 107}, + {"msanread", funcTag, 107}, + {"msanwrite", funcTag, 107}, } func runtimeTypes() []*Type { - var typs [109]*Type + var typs [108]*Type typs[0] = bytetype typs[1] = typPtr(typs[0]) typs[2] = Types[TANY] @@ -179,68 +178,67 @@ func runtimeTypes() []*Type { typs[43] = typSlice(typs[42]) typs[44] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[43])}, []*Node{anonfield(typs[6])}) typs[45] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[6])}, []*Node{anonfield(typs[39])}) - typs[46] = functype(nil, []*Node{anonfield(typs[6])}, []*Node{anonfield(typs[39])}) - typs[47] = typArray(typs[42], 32) - typs[48] = typPtr(typs[47]) - typs[49] = functype(nil, []*Node{anonfield(typs[48]), anonfield(typs[6])}, []*Node{anonfield(typs[43])}) - typs[50] = functype(nil, []*Node{anonfield(typs[6]), anonfield(typs[33])}, []*Node{anonfield(typs[42]), anonfield(typs[33])}) - typs[51] = Types[TUINTPTR] - typs[52] = functype(nil, []*Node{anonfield(typs[2]), anonfield(typs[2]), anonfield(typs[51])}, []*Node{anonfield(typs[33])}) - typs[53] = functype(nil, []*Node{anonfield(typs[2]), anonfield(typs[2])}, []*Node{anonfield(typs[33])}) - typs[54] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])}) - typs[55] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])}) - typs[56] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2]), anonfield(typs[3])}, nil) - typs[57] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2]), anonfield(typs[3])}, []*Node{anonfield(typs[13])}) - typs[58] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil) - typs[59] = functype(nil, []*Node{anonfield(typs[2]), anonfield(typs[2])}, []*Node{anonfield(typs[13])}) - typs[60] = typMap(typs[2], typs[2]) - typs[61] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[17]), anonfield(typs[3]), 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[13])}) - typs[66] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[60]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[13])}) - typs[67] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[60]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[13])}) - typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[60]), anonfield(typs[3])}, nil) - typs[69] = functype(nil, []*Node{anonfield(typs[3])}, nil) - typs[70] = typChan(typs[2], Cboth) - typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[17])}, []*Node{anonfield(typs[70])}) - typs[72] = typChan(typs[2], Crecv) - typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[72]), anonfield(typs[3])}, nil) - typs[74] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[72]), anonfield(typs[3])}, []*Node{anonfield(typs[13])}) - typs[75] = typChan(typs[2], Csend) - typs[76] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[75]), anonfield(typs[3])}, nil) - typs[77] = tostruct([]*Node{namedfield("enabled", typs[13]), namedfield("needed", typs[13]), namedfield("cgo", typs[13])}) - typs[78] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[2])}, nil) - typs[79] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil) - typs[80] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2]), anonfield(typs[2])}, []*Node{anonfield(typs[33])}) - typs[81] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[75]), anonfield(typs[3])}, []*Node{anonfield(typs[13])}) - typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[72])}, []*Node{anonfield(typs[13])}) - typs[83] = typPtr(typs[13]) - typs[84] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[83]), anonfield(typs[72])}, []*Node{anonfield(typs[13])}) - typs[85] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[17]), anonfield(typs[10])}, nil) - typs[86] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[72]), anonfield(typs[3]), anonfield(typs[83])}, []*Node{anonfield(typs[13])}) - typs[87] = functype(nil, []*Node{anonfield(typs[1])}, []*Node{anonfield(typs[13])}) - typs[88] = functype(nil, []*Node{anonfield(typs[1])}, nil) - typs[89] = typSlice(typs[2]) - typs[90] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[33]), anonfield(typs[33])}, []*Node{anonfield(typs[89])}) - typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[17]), anonfield(typs[17])}, []*Node{anonfield(typs[89])}) - typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[89]), anonfield(typs[33])}, []*Node{anonfield(typs[89])}) - typs[93] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[51])}, nil) - typs[94] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[51])}, nil) - typs[95] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[51])}, []*Node{anonfield(typs[13])}) - typs[96] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[13])}) - typs[97] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[17])}, []*Node{anonfield(typs[17])}) - typs[98] = functype(nil, []*Node{anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[19])}) - typs[99] = functype(nil, []*Node{anonfield(typs[15])}, []*Node{anonfield(typs[17])}) - typs[100] = functype(nil, []*Node{anonfield(typs[15])}, []*Node{anonfield(typs[19])}) - typs[101] = Types[TUINT32] - typs[102] = functype(nil, []*Node{anonfield(typs[15])}, []*Node{anonfield(typs[101])}) - typs[103] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[15])}) - typs[104] = functype(nil, []*Node{anonfield(typs[19])}, []*Node{anonfield(typs[15])}) - typs[105] = functype(nil, []*Node{anonfield(typs[101])}, []*Node{anonfield(typs[15])}) - typs[106] = functype(nil, []*Node{anonfield(typs[21]), anonfield(typs[21])}, []*Node{anonfield(typs[21])}) - typs[107] = functype(nil, []*Node{anonfield(typs[51])}, nil) - typs[108] = functype(nil, []*Node{anonfield(typs[51]), anonfield(typs[51])}, nil) + typs[46] = typArray(typs[42], 32) + typs[47] = typPtr(typs[46]) + typs[48] = functype(nil, []*Node{anonfield(typs[47]), anonfield(typs[6])}, []*Node{anonfield(typs[43])}) + typs[49] = functype(nil, []*Node{anonfield(typs[6]), anonfield(typs[33])}, []*Node{anonfield(typs[42]), anonfield(typs[33])}) + typs[50] = Types[TUINTPTR] + typs[51] = functype(nil, []*Node{anonfield(typs[2]), anonfield(typs[2]), anonfield(typs[50])}, []*Node{anonfield(typs[33])}) + typs[52] = functype(nil, []*Node{anonfield(typs[2]), anonfield(typs[2])}, []*Node{anonfield(typs[33])}) + typs[53] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])}) + typs[54] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])}) + typs[55] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2]), anonfield(typs[3])}, nil) + typs[56] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2]), anonfield(typs[3])}, []*Node{anonfield(typs[13])}) + typs[57] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil) + typs[58] = functype(nil, []*Node{anonfield(typs[2]), anonfield(typs[2])}, []*Node{anonfield(typs[13])}) + typs[59] = typMap(typs[2], typs[2]) + typs[60] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[17]), anonfield(typs[3]), 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[13])}) + typs[65] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[59]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[13])}) + typs[66] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[59]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[13])}) + typs[67] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[59]), anonfield(typs[3])}, nil) + typs[68] = functype(nil, []*Node{anonfield(typs[3])}, nil) + typs[69] = typChan(typs[2], Cboth) + typs[70] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[17])}, []*Node{anonfield(typs[69])}) + typs[71] = typChan(typs[2], Crecv) + typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[71]), anonfield(typs[3])}, nil) + typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[71]), anonfield(typs[3])}, []*Node{anonfield(typs[13])}) + typs[74] = typChan(typs[2], Csend) + typs[75] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[74]), anonfield(typs[3])}, nil) + typs[76] = tostruct([]*Node{namedfield("enabled", typs[13]), namedfield("needed", typs[13]), namedfield("cgo", typs[13])}) + typs[77] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[2])}, nil) + typs[78] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil) + typs[79] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2]), anonfield(typs[2])}, []*Node{anonfield(typs[33])}) + typs[80] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[74]), anonfield(typs[3])}, []*Node{anonfield(typs[13])}) + typs[81] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[71])}, []*Node{anonfield(typs[13])}) + typs[82] = typPtr(typs[13]) + typs[83] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[82]), anonfield(typs[71])}, []*Node{anonfield(typs[13])}) + typs[84] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[17]), anonfield(typs[10])}, nil) + typs[85] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[71]), anonfield(typs[3]), anonfield(typs[82])}, []*Node{anonfield(typs[13])}) + typs[86] = functype(nil, []*Node{anonfield(typs[1])}, []*Node{anonfield(typs[13])}) + typs[87] = functype(nil, []*Node{anonfield(typs[1])}, nil) + typs[88] = typSlice(typs[2]) + typs[89] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[33]), anonfield(typs[33])}, []*Node{anonfield(typs[88])}) + typs[90] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[17]), anonfield(typs[17])}, []*Node{anonfield(typs[88])}) + typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[88]), anonfield(typs[33])}, []*Node{anonfield(typs[88])}) + typs[92] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[50])}, nil) + typs[93] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[50])}, nil) + typs[94] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[50])}, []*Node{anonfield(typs[13])}) + typs[95] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[13])}) + typs[96] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[17])}, []*Node{anonfield(typs[17])}) + typs[97] = functype(nil, []*Node{anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[19])}) + typs[98] = functype(nil, []*Node{anonfield(typs[15])}, []*Node{anonfield(typs[17])}) + typs[99] = functype(nil, []*Node{anonfield(typs[15])}, []*Node{anonfield(typs[19])}) + typs[100] = Types[TUINT32] + typs[101] = functype(nil, []*Node{anonfield(typs[15])}, []*Node{anonfield(typs[100])}) + typs[102] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[15])}) + typs[103] = functype(nil, []*Node{anonfield(typs[19])}, []*Node{anonfield(typs[15])}) + typs[104] = functype(nil, []*Node{anonfield(typs[100])}, []*Node{anonfield(typs[15])}) + typs[105] = functype(nil, []*Node{anonfield(typs[21]), anonfield(typs[21])}, []*Node{anonfield(typs[21])}) + typs[106] = functype(nil, []*Node{anonfield(typs[50])}, nil) + typs[107] = functype(nil, []*Node{anonfield(typs[50]), anonfield(typs[50])}, nil) return typs[:] } diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go index ae7e98693b..07be2d2da3 100644 --- a/src/cmd/compile/internal/gc/builtin/runtime.go +++ b/src/cmd/compile/internal/gc/builtin/runtime.go @@ -51,7 +51,6 @@ func slicebytetostring(*[32]byte, []byte) string func slicebytetostringtmp([]byte) string func slicerunetostring(*[32]byte, []rune) string func stringtoslicebyte(*[32]byte, string) []byte -func stringtoslicebytetmp(string) []byte func stringtoslicerune(*[32]rune, string) []rune func decoderune(string, int) (retv rune, retk int) func slicecopy(to any, fr any, wid uintptr) int diff --git a/src/cmd/compile/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go index 8f13c7ac92..f3004403b2 100644 --- a/src/cmd/compile/internal/gc/racewalk.go +++ b/src/cmd/compile/internal/gc/racewalk.go @@ -314,6 +314,10 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) { instrumentnode(&n.Left, init, 0, 0) goto ret + case OSTRARRAYBYTETMP: + instrumentnode(&n.Left, init, 0, 0) + goto ret + // should not appear in AST by now case OSEND, ORECV, diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index df6a6700b6..1afbce2835 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -1428,6 +1428,11 @@ func (s *state) expr(n *Node) *ssa.Value { ptr := s.newValue1(ssa.OpSlicePtr, ptrto(Types[TUINT8]), slice) len := s.newValue1(ssa.OpSliceLen, Types[TINT], slice) return s.newValue2(ssa.OpStringMake, n.Type, ptr, len) + case OSTRARRAYBYTETMP: + str := s.expr(n.Left) + ptr := s.newValue1(ssa.OpStringPtr, ptrto(Types[TUINT8]), str) + len := s.newValue1(ssa.OpStringLen, Types[TINT], str) + return s.newValue3(ssa.OpSliceMake, n.Type, ptr, len, len) case OCFUNC: aux := s.lookupSymbol(n, &ssa.ExternSymbol{Typ: n.Type, Sym: n.Left.Sym}) return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb) diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 27cbf9152a..f0f4a99892 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -1660,9 +1660,15 @@ opswitch: n = mkcall("stringtoslicebyte", n.Type, init, a, conv(n.Left, Types[TSTRING])) - // stringtoslicebytetmp(string) []byte; case OSTRARRAYBYTETMP: - n = mkcall("stringtoslicebytetmp", n.Type, init, conv(n.Left, Types[TSTRING])) + // []byte(string) conversion that creates a slice + // referring to the actual string bytes. + // This conversion is handled later by the backend and + // is only for use by internal compiler optimizations + // that know that the slice won't be mutated. + // The only such case today is: + // for i, c := range []byte(string) + n.Left = walkexpr(n.Left, init) // stringtoslicerune(*[32]rune, string) []rune case OSTRARRAYRUNE: diff --git a/src/runtime/string.go b/src/runtime/string.go index c7a9d27711..4cf165bb87 100644 --- a/src/runtime/string.go +++ b/src/runtime/string.go @@ -147,18 +147,6 @@ func stringtoslicebyte(buf *tmpBuf, s string) []byte { return b } -func stringtoslicebytetmp(s string) []byte { - // Return a slice referring to the actual string bytes. - // This is only for use by internal compiler optimizations - // that know that the slice won't be mutated. - // The only such case today is: - // for i, c := range []byte(str) - - str := stringStructOf(&s) - ret := slice{array: str.str, len: str.len, cap: str.len} - return *(*[]byte)(unsafe.Pointer(&ret)) -} - func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune { // two passes. // unlike slicerunetostring, no race because strings are immutable. diff --git a/test/range.go b/test/range.go index af89edac54..bae7a1c3c9 100644 --- a/test/range.go +++ b/test/range.go @@ -110,6 +110,30 @@ func testslice2() { } } +// test that range over []byte(string) only evaluates +// the expression after "range" once. + +func makenumstring() string { + nmake++ + return "\x01\x02\x03\x04\x05" +} + +func testslice3() { + s := byte(0) + nmake = 0 + for _, v := range []byte(makenumstring()) { + s += v + } + if nmake != 1 { + println("range called makenumstring", nmake, "times") + panic("fail") + } + if s != 15 { + println("wrong sum ranging over []byte(makenumstring)", s) + panic("fail") + } +} + // test that range over array only evaluates // the expression after "range" once. @@ -392,6 +416,7 @@ func main() { testslice() testslice1() testslice2() + testslice3() teststring() teststring1() teststring2() -- 2.48.1