1
0
mirror of https://github.com/golang/go synced 2024-11-25 23:58:02 -07:00

cmd/compile: optimize []byte(string1 + string2)

This CL optimizes the compilation of string-to-bytes conversion in the
case of string additions.

Fixes #62407

Change-Id: Ic47df758478e5d061880620025c4ec7dbbff8a64
Reviewed-on: https://go-review.googlesource.com/c/go/+/527935
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Keith Randall <khr@golang.org>
Auto-Submit: Keith Randall <khr@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Tim King <taking@google.com>
This commit is contained in:
Paschalis Tsilias 2023-09-13 12:44:17 +03:00 committed by Gopher Robot
parent 3da4281df1
commit fe69121bc5
8 changed files with 438 additions and 287 deletions

View File

@ -0,0 +1,62 @@
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package test
import (
"reflect"
"testing"
)
//go:noinline
func foo() string { return "foo" }
//go:noinline
func empty() string { return "" }
func TestConcatBytes(t *testing.T) {
empty := empty()
s := foo()
tests := map[string]struct {
got []byte
want []byte
}{
"two empty elements": {got: []byte(empty + empty), want: []byte{}},
"two nonempty elements": {got: []byte(s + s), want: []byte("foofoo")},
"one empty and one nonempty element": {got: []byte(s + empty), want: []byte("foo")},
"multiple empty elements": {got: []byte(empty + empty + empty + empty + empty + empty), want: []byte{}},
"multiple nonempty elements": {got: []byte("1" + "2" + "3" + "4" + "5" + "6"), want: []byte("123456")},
}
for name, test := range tests {
if !reflect.DeepEqual(test.got, test.want) {
t.Errorf("[%s] got: %s, want: %s", name, test.got, test.want)
}
}
}
func TestConcatBytesAllocations(t *testing.T) {
empty := empty()
s := foo()
tests := map[string]struct {
f func() []byte
allocs float64
}{
"two empty elements": {f: func() []byte { return []byte(empty + empty) }, allocs: 0},
"multiple empty elements": {f: func() []byte { return []byte(empty + empty + empty + empty + empty + empty) }, allocs: 0},
"two elements": {f: func() []byte { return []byte(s + s) }, allocs: 1},
"three elements": {f: func() []byte { return []byte(s + s + s) }, allocs: 1},
"four elements": {f: func() []byte { return []byte(s + s + s + s) }, allocs: 1},
"five elements": {f: func() []byte { return []byte(s + s + s + s + s) }, allocs: 1},
"one empty and one nonempty element": {f: func() []byte { return []byte(s + empty) }, allocs: 1},
"two empty and two nonempty element": {f: func() []byte { return []byte(s + empty + s + empty) }, allocs: 1},
}
for name, test := range tests {
allocs := testing.AllocsPerRun(100, func() { test.f() })
if allocs != test.allocs {
t.Errorf("concatbytes [%s]: %v allocs, want %v", name, allocs, test.allocs)
}
}
}

View File

@ -71,6 +71,12 @@ func concatstring4(*[32]byte, string, string, string, string) string
func concatstring5(*[32]byte, string, string, string, string, string) string
func concatstrings(*[32]byte, []string) string
func concatbyte2(string, string) []byte
func concatbyte3(string, string, string) []byte
func concatbyte4(string, string, string, string) []byte
func concatbyte5(string, string, string, string, string) []byte
func concatbytes([]string) []byte
func cmpstring(string, string) int
func intstring(*[4]byte, int64) string
func slicebytetostring(buf *[32]byte, ptr *byte, n int) string

View File

@ -76,168 +76,173 @@ var runtimeDecls = [...]struct {
{"concatstring4", funcTag, 36},
{"concatstring5", funcTag, 37},
{"concatstrings", funcTag, 39},
{"cmpstring", funcTag, 40},
{"intstring", funcTag, 43},
{"slicebytetostring", funcTag, 44},
{"slicebytetostringtmp", funcTag, 45},
{"slicerunetostring", funcTag, 48},
{"stringtoslicebyte", funcTag, 50},
{"stringtoslicerune", funcTag, 53},
{"slicecopy", funcTag, 54},
{"decoderune", funcTag, 55},
{"countrunes", funcTag, 56},
{"convT", funcTag, 57},
{"convTnoptr", funcTag, 57},
{"convT16", funcTag, 59},
{"convT32", funcTag, 61},
{"convT64", funcTag, 62},
{"convTstring", funcTag, 63},
{"convTslice", funcTag, 66},
{"assertE2I", funcTag, 67},
{"assertE2I2", funcTag, 67},
{"panicdottypeE", funcTag, 68},
{"panicdottypeI", funcTag, 68},
{"panicnildottype", funcTag, 69},
{"typeAssert", funcTag, 67},
{"interfaceSwitch", funcTag, 70},
{"ifaceeq", funcTag, 72},
{"efaceeq", funcTag, 72},
{"panicrangestate", funcTag, 73},
{"deferrangefunc", funcTag, 74},
{"rand32", funcTag, 75},
{"makemap64", funcTag, 77},
{"makemap", funcTag, 78},
{"makemap_small", funcTag, 79},
{"mapaccess1", funcTag, 80},
{"mapaccess1_fast32", funcTag, 81},
{"mapaccess1_fast64", funcTag, 82},
{"mapaccess1_faststr", funcTag, 83},
{"mapaccess1_fat", funcTag, 84},
{"mapaccess2", funcTag, 85},
{"mapaccess2_fast32", funcTag, 86},
{"mapaccess2_fast64", funcTag, 87},
{"mapaccess2_faststr", funcTag, 88},
{"mapaccess2_fat", funcTag, 89},
{"mapassign", funcTag, 80},
{"mapassign_fast32", funcTag, 81},
{"mapassign_fast32ptr", funcTag, 90},
{"mapassign_fast64", funcTag, 82},
{"mapassign_fast64ptr", funcTag, 90},
{"mapassign_faststr", funcTag, 83},
{"mapiterinit", funcTag, 91},
{"mapdelete", funcTag, 91},
{"mapdelete_fast32", funcTag, 92},
{"mapdelete_fast64", funcTag, 93},
{"mapdelete_faststr", funcTag, 94},
{"mapiternext", funcTag, 95},
{"mapclear", funcTag, 96},
{"makechan64", funcTag, 98},
{"makechan", funcTag, 99},
{"chanrecv1", funcTag, 101},
{"chanrecv2", funcTag, 102},
{"chansend1", funcTag, 104},
{"closechan", funcTag, 105},
{"chanlen", funcTag, 106},
{"chancap", funcTag, 106},
{"writeBarrier", varTag, 108},
{"typedmemmove", funcTag, 109},
{"typedmemclr", funcTag, 110},
{"typedslicecopy", funcTag, 111},
{"selectnbsend", funcTag, 112},
{"selectnbrecv", funcTag, 113},
{"selectsetpc", funcTag, 114},
{"selectgo", funcTag, 115},
{"concatbyte2", funcTag, 41},
{"concatbyte3", funcTag, 42},
{"concatbyte4", funcTag, 43},
{"concatbyte5", funcTag, 44},
{"concatbytes", funcTag, 45},
{"cmpstring", funcTag, 46},
{"intstring", funcTag, 49},
{"slicebytetostring", funcTag, 50},
{"slicebytetostringtmp", funcTag, 51},
{"slicerunetostring", funcTag, 54},
{"stringtoslicebyte", funcTag, 55},
{"stringtoslicerune", funcTag, 58},
{"slicecopy", funcTag, 59},
{"decoderune", funcTag, 60},
{"countrunes", funcTag, 61},
{"convT", funcTag, 62},
{"convTnoptr", funcTag, 62},
{"convT16", funcTag, 64},
{"convT32", funcTag, 66},
{"convT64", funcTag, 67},
{"convTstring", funcTag, 68},
{"convTslice", funcTag, 71},
{"assertE2I", funcTag, 72},
{"assertE2I2", funcTag, 72},
{"panicdottypeE", funcTag, 73},
{"panicdottypeI", funcTag, 73},
{"panicnildottype", funcTag, 74},
{"typeAssert", funcTag, 72},
{"interfaceSwitch", funcTag, 75},
{"ifaceeq", funcTag, 77},
{"efaceeq", funcTag, 77},
{"panicrangestate", funcTag, 78},
{"deferrangefunc", funcTag, 79},
{"rand32", funcTag, 80},
{"makemap64", funcTag, 82},
{"makemap", funcTag, 83},
{"makemap_small", funcTag, 84},
{"mapaccess1", funcTag, 85},
{"mapaccess1_fast32", funcTag, 86},
{"mapaccess1_fast64", funcTag, 87},
{"mapaccess1_faststr", funcTag, 88},
{"mapaccess1_fat", funcTag, 89},
{"mapaccess2", funcTag, 90},
{"mapaccess2_fast32", funcTag, 91},
{"mapaccess2_fast64", funcTag, 92},
{"mapaccess2_faststr", funcTag, 93},
{"mapaccess2_fat", funcTag, 94},
{"mapassign", funcTag, 85},
{"mapassign_fast32", funcTag, 86},
{"mapassign_fast32ptr", funcTag, 95},
{"mapassign_fast64", funcTag, 87},
{"mapassign_fast64ptr", funcTag, 95},
{"mapassign_faststr", funcTag, 88},
{"mapiterinit", funcTag, 96},
{"mapdelete", funcTag, 96},
{"mapdelete_fast32", funcTag, 97},
{"mapdelete_fast64", funcTag, 98},
{"mapdelete_faststr", funcTag, 99},
{"mapiternext", funcTag, 100},
{"mapclear", funcTag, 101},
{"makechan64", funcTag, 103},
{"makechan", funcTag, 104},
{"chanrecv1", funcTag, 106},
{"chanrecv2", funcTag, 107},
{"chansend1", funcTag, 109},
{"closechan", funcTag, 110},
{"chanlen", funcTag, 111},
{"chancap", funcTag, 111},
{"writeBarrier", varTag, 113},
{"typedmemmove", funcTag, 114},
{"typedmemclr", funcTag, 115},
{"typedslicecopy", funcTag, 116},
{"selectnbsend", funcTag, 117},
{"selectnbrecv", funcTag, 118},
{"selectsetpc", funcTag, 119},
{"selectgo", funcTag, 120},
{"block", funcTag, 9},
{"makeslice", funcTag, 116},
{"makeslice64", funcTag, 117},
{"makeslicecopy", funcTag, 118},
{"growslice", funcTag, 120},
{"unsafeslicecheckptr", funcTag, 121},
{"makeslice", funcTag, 121},
{"makeslice64", funcTag, 122},
{"makeslicecopy", funcTag, 123},
{"growslice", funcTag, 125},
{"unsafeslicecheckptr", funcTag, 126},
{"panicunsafeslicelen", funcTag, 9},
{"panicunsafeslicenilptr", funcTag, 9},
{"unsafestringcheckptr", funcTag, 122},
{"unsafestringcheckptr", funcTag, 127},
{"panicunsafestringlen", funcTag, 9},
{"panicunsafestringnilptr", funcTag, 9},
{"memmove", funcTag, 123},
{"memclrNoHeapPointers", funcTag, 124},
{"memclrHasPointers", funcTag, 124},
{"memequal", funcTag, 125},
{"memequal0", funcTag, 126},
{"memequal8", funcTag, 126},
{"memequal16", funcTag, 126},
{"memequal32", funcTag, 126},
{"memequal64", funcTag, 126},
{"memequal128", funcTag, 126},
{"f32equal", funcTag, 127},
{"f64equal", funcTag, 127},
{"c64equal", funcTag, 127},
{"c128equal", funcTag, 127},
{"strequal", funcTag, 127},
{"interequal", funcTag, 127},
{"nilinterequal", funcTag, 127},
{"memhash", funcTag, 128},
{"memhash0", funcTag, 129},
{"memhash8", funcTag, 129},
{"memhash16", funcTag, 129},
{"memhash32", funcTag, 129},
{"memhash64", funcTag, 129},
{"memhash128", funcTag, 129},
{"f32hash", funcTag, 130},
{"f64hash", funcTag, 130},
{"c64hash", funcTag, 130},
{"c128hash", funcTag, 130},
{"strhash", funcTag, 130},
{"interhash", funcTag, 130},
{"nilinterhash", funcTag, 130},
{"int64div", funcTag, 131},
{"uint64div", funcTag, 132},
{"int64mod", funcTag, 131},
{"uint64mod", funcTag, 132},
{"float64toint64", funcTag, 133},
{"float64touint64", funcTag, 134},
{"float64touint32", funcTag, 135},
{"int64tofloat64", funcTag, 136},
{"int64tofloat32", funcTag, 138},
{"uint64tofloat64", funcTag, 139},
{"uint64tofloat32", funcTag, 140},
{"uint32tofloat64", funcTag, 141},
{"complex128div", funcTag, 142},
{"getcallerpc", funcTag, 143},
{"getcallersp", funcTag, 143},
{"memmove", funcTag, 128},
{"memclrNoHeapPointers", funcTag, 129},
{"memclrHasPointers", funcTag, 129},
{"memequal", funcTag, 130},
{"memequal0", funcTag, 131},
{"memequal8", funcTag, 131},
{"memequal16", funcTag, 131},
{"memequal32", funcTag, 131},
{"memequal64", funcTag, 131},
{"memequal128", funcTag, 131},
{"f32equal", funcTag, 132},
{"f64equal", funcTag, 132},
{"c64equal", funcTag, 132},
{"c128equal", funcTag, 132},
{"strequal", funcTag, 132},
{"interequal", funcTag, 132},
{"nilinterequal", funcTag, 132},
{"memhash", funcTag, 133},
{"memhash0", funcTag, 134},
{"memhash8", funcTag, 134},
{"memhash16", funcTag, 134},
{"memhash32", funcTag, 134},
{"memhash64", funcTag, 134},
{"memhash128", funcTag, 134},
{"f32hash", funcTag, 135},
{"f64hash", funcTag, 135},
{"c64hash", funcTag, 135},
{"c128hash", funcTag, 135},
{"strhash", funcTag, 135},
{"interhash", funcTag, 135},
{"nilinterhash", funcTag, 135},
{"int64div", funcTag, 136},
{"uint64div", funcTag, 137},
{"int64mod", funcTag, 136},
{"uint64mod", funcTag, 137},
{"float64toint64", funcTag, 138},
{"float64touint64", funcTag, 139},
{"float64touint32", funcTag, 140},
{"int64tofloat64", funcTag, 141},
{"int64tofloat32", funcTag, 143},
{"uint64tofloat64", funcTag, 144},
{"uint64tofloat32", funcTag, 145},
{"uint32tofloat64", funcTag, 146},
{"complex128div", funcTag, 147},
{"getcallerpc", funcTag, 148},
{"getcallersp", funcTag, 148},
{"racefuncenter", funcTag, 31},
{"racefuncexit", funcTag, 9},
{"raceread", funcTag, 31},
{"racewrite", funcTag, 31},
{"racereadrange", funcTag, 144},
{"racewriterange", funcTag, 144},
{"msanread", funcTag, 144},
{"msanwrite", funcTag, 144},
{"msanmove", funcTag, 145},
{"asanread", funcTag, 144},
{"asanwrite", funcTag, 144},
{"checkptrAlignment", funcTag, 146},
{"checkptrArithmetic", funcTag, 148},
{"libfuzzerTraceCmp1", funcTag, 149},
{"libfuzzerTraceCmp2", funcTag, 150},
{"libfuzzerTraceCmp4", funcTag, 151},
{"libfuzzerTraceCmp8", funcTag, 152},
{"libfuzzerTraceConstCmp1", funcTag, 149},
{"libfuzzerTraceConstCmp2", funcTag, 150},
{"libfuzzerTraceConstCmp4", funcTag, 151},
{"libfuzzerTraceConstCmp8", funcTag, 152},
{"libfuzzerHookStrCmp", funcTag, 153},
{"libfuzzerHookEqualFold", funcTag, 153},
{"addCovMeta", funcTag, 155},
{"racereadrange", funcTag, 149},
{"racewriterange", funcTag, 149},
{"msanread", funcTag, 149},
{"msanwrite", funcTag, 149},
{"msanmove", funcTag, 150},
{"asanread", funcTag, 149},
{"asanwrite", funcTag, 149},
{"checkptrAlignment", funcTag, 151},
{"checkptrArithmetic", funcTag, 153},
{"libfuzzerTraceCmp1", funcTag, 154},
{"libfuzzerTraceCmp2", funcTag, 155},
{"libfuzzerTraceCmp4", funcTag, 156},
{"libfuzzerTraceCmp8", funcTag, 157},
{"libfuzzerTraceConstCmp1", funcTag, 154},
{"libfuzzerTraceConstCmp2", funcTag, 155},
{"libfuzzerTraceConstCmp4", funcTag, 156},
{"libfuzzerTraceConstCmp8", funcTag, 157},
{"libfuzzerHookStrCmp", funcTag, 158},
{"libfuzzerHookEqualFold", funcTag, 158},
{"addCovMeta", funcTag, 160},
{"x86HasPOPCNT", varTag, 6},
{"x86HasSSE41", varTag, 6},
{"x86HasFMA", varTag, 6},
{"armHasVFPv4", varTag, 6},
{"arm64HasATOMICS", varTag, 6},
{"asanregisterglobals", funcTag, 124},
{"asanregisterglobals", funcTag, 129},
}
func runtimeTypes() []*types.Type {
var typs [156]*types.Type
var typs [161]*types.Type
typs[0] = types.ByteType
typs[1] = types.NewPtr(typs[0])
typs[2] = types.Types[types.TANY]
@ -278,122 +283,127 @@ func runtimeTypes() []*types.Type {
typs[37] = newSig(params(typs[33], typs[28], typs[28], typs[28], typs[28], typs[28]), params(typs[28]))
typs[38] = types.NewSlice(typs[28])
typs[39] = newSig(params(typs[33], typs[38]), params(typs[28]))
typs[40] = newSig(params(typs[28], typs[28]), params(typs[15]))
typs[41] = types.NewArray(typs[0], 4)
typs[42] = types.NewPtr(typs[41])
typs[43] = newSig(params(typs[42], typs[22]), params(typs[28]))
typs[44] = newSig(params(typs[33], typs[1], typs[15]), params(typs[28]))
typs[45] = newSig(params(typs[1], typs[15]), params(typs[28]))
typs[46] = types.RuneType
typs[47] = types.NewSlice(typs[46])
typs[48] = newSig(params(typs[33], typs[47]), params(typs[28]))
typs[49] = types.NewSlice(typs[0])
typs[50] = newSig(params(typs[33], typs[28]), params(typs[49]))
typs[51] = types.NewArray(typs[46], 32)
typs[52] = types.NewPtr(typs[51])
typs[53] = newSig(params(typs[52], typs[28]), params(typs[47]))
typs[54] = newSig(params(typs[3], typs[15], typs[3], typs[15], typs[5]), params(typs[15]))
typs[55] = newSig(params(typs[28], typs[15]), params(typs[46], typs[15]))
typs[56] = newSig(params(typs[28]), params(typs[15]))
typs[57] = newSig(params(typs[1], typs[3]), params(typs[7]))
typs[58] = types.Types[types.TUINT16]
typs[59] = newSig(params(typs[58]), params(typs[7]))
typs[60] = types.Types[types.TUINT32]
typs[61] = newSig(params(typs[60]), params(typs[7]))
typs[62] = newSig(params(typs[24]), params(typs[7]))
typs[63] = newSig(params(typs[28]), params(typs[7]))
typs[64] = types.Types[types.TUINT8]
typs[65] = types.NewSlice(typs[64])
typs[40] = types.NewSlice(typs[0])
typs[41] = newSig(params(typs[28], typs[28]), params(typs[40]))
typs[42] = newSig(params(typs[28], typs[28], typs[28]), params(typs[40]))
typs[43] = newSig(params(typs[28], typs[28], typs[28], typs[28]), params(typs[40]))
typs[44] = newSig(params(typs[28], typs[28], typs[28], typs[28], typs[28]), params(typs[40]))
typs[45] = newSig(params(typs[38]), params(typs[40]))
typs[46] = newSig(params(typs[28], typs[28]), params(typs[15]))
typs[47] = types.NewArray(typs[0], 4)
typs[48] = types.NewPtr(typs[47])
typs[49] = newSig(params(typs[48], typs[22]), params(typs[28]))
typs[50] = newSig(params(typs[33], typs[1], typs[15]), params(typs[28]))
typs[51] = newSig(params(typs[1], typs[15]), params(typs[28]))
typs[52] = types.RuneType
typs[53] = types.NewSlice(typs[52])
typs[54] = newSig(params(typs[33], typs[53]), params(typs[28]))
typs[55] = newSig(params(typs[33], typs[28]), params(typs[40]))
typs[56] = types.NewArray(typs[52], 32)
typs[57] = types.NewPtr(typs[56])
typs[58] = newSig(params(typs[57], typs[28]), params(typs[53]))
typs[59] = newSig(params(typs[3], typs[15], typs[3], typs[15], typs[5]), params(typs[15]))
typs[60] = newSig(params(typs[28], typs[15]), params(typs[52], typs[15]))
typs[61] = newSig(params(typs[28]), params(typs[15]))
typs[62] = newSig(params(typs[1], typs[3]), params(typs[7]))
typs[63] = types.Types[types.TUINT16]
typs[64] = newSig(params(typs[63]), params(typs[7]))
typs[65] = types.Types[types.TUINT32]
typs[66] = newSig(params(typs[65]), params(typs[7]))
typs[67] = newSig(params(typs[1], typs[1]), params(typs[1]))
typs[68] = newSig(params(typs[1], typs[1], typs[1]), nil)
typs[69] = newSig(params(typs[1]), nil)
typs[70] = newSig(params(typs[1], typs[1]), params(typs[15], typs[1]))
typs[71] = types.NewPtr(typs[5])
typs[72] = newSig(params(typs[71], typs[7], typs[7]), params(typs[6]))
typs[73] = newSig(params(typs[15]), nil)
typs[74] = newSig(nil, params(typs[10]))
typs[75] = newSig(nil, params(typs[60]))
typs[76] = types.NewMap(typs[2], typs[2])
typs[77] = newSig(params(typs[1], typs[22], typs[3]), params(typs[76]))
typs[78] = newSig(params(typs[1], typs[15], typs[3]), params(typs[76]))
typs[79] = newSig(nil, params(typs[76]))
typs[80] = newSig(params(typs[1], typs[76], typs[3]), params(typs[3]))
typs[81] = newSig(params(typs[1], typs[76], typs[60]), params(typs[3]))
typs[82] = newSig(params(typs[1], typs[76], typs[24]), params(typs[3]))
typs[83] = newSig(params(typs[1], typs[76], typs[28]), params(typs[3]))
typs[84] = newSig(params(typs[1], typs[76], typs[3], typs[1]), params(typs[3]))
typs[85] = newSig(params(typs[1], typs[76], typs[3]), params(typs[3], typs[6]))
typs[86] = newSig(params(typs[1], typs[76], typs[60]), params(typs[3], typs[6]))
typs[87] = newSig(params(typs[1], typs[76], typs[24]), params(typs[3], typs[6]))
typs[88] = newSig(params(typs[1], typs[76], typs[28]), params(typs[3], typs[6]))
typs[89] = newSig(params(typs[1], typs[76], typs[3], typs[1]), params(typs[3], typs[6]))
typs[90] = newSig(params(typs[1], typs[76], typs[7]), params(typs[3]))
typs[91] = newSig(params(typs[1], typs[76], typs[3]), nil)
typs[92] = newSig(params(typs[1], typs[76], typs[60]), nil)
typs[93] = newSig(params(typs[1], typs[76], typs[24]), nil)
typs[94] = newSig(params(typs[1], typs[76], typs[28]), nil)
typs[95] = newSig(params(typs[3]), nil)
typs[96] = newSig(params(typs[1], typs[76]), nil)
typs[97] = types.NewChan(typs[2], types.Cboth)
typs[98] = newSig(params(typs[1], typs[22]), params(typs[97]))
typs[99] = newSig(params(typs[1], typs[15]), params(typs[97]))
typs[100] = types.NewChan(typs[2], types.Crecv)
typs[101] = newSig(params(typs[100], typs[3]), nil)
typs[102] = newSig(params(typs[100], typs[3]), params(typs[6]))
typs[103] = types.NewChan(typs[2], types.Csend)
typs[104] = newSig(params(typs[103], typs[3]), nil)
typs[105] = newSig(params(typs[103]), nil)
typs[106] = newSig(params(typs[2]), params(typs[15]))
typs[107] = types.NewArray(typs[0], 3)
typs[108] = types.NewStruct([]*types.Field{types.NewField(src.NoXPos, Lookup("enabled"), typs[6]), types.NewField(src.NoXPos, Lookup("pad"), typs[107]), types.NewField(src.NoXPos, Lookup("cgo"), typs[6]), types.NewField(src.NoXPos, Lookup("alignme"), typs[24])})
typs[109] = newSig(params(typs[1], typs[3], typs[3]), nil)
typs[110] = newSig(params(typs[1], typs[3]), nil)
typs[111] = newSig(params(typs[1], typs[3], typs[15], typs[3], typs[15]), params(typs[15]))
typs[112] = newSig(params(typs[103], typs[3]), params(typs[6]))
typs[113] = newSig(params(typs[3], typs[100]), params(typs[6], typs[6]))
typs[114] = newSig(params(typs[71]), nil)
typs[115] = newSig(params(typs[1], typs[1], typs[71], typs[15], typs[15], typs[6]), params(typs[15], typs[6]))
typs[116] = newSig(params(typs[1], typs[15], typs[15]), params(typs[7]))
typs[117] = newSig(params(typs[1], typs[22], typs[22]), params(typs[7]))
typs[118] = newSig(params(typs[1], typs[15], typs[15], typs[7]), params(typs[7]))
typs[119] = types.NewSlice(typs[2])
typs[120] = newSig(params(typs[3], typs[15], typs[15], typs[15], typs[1]), params(typs[119]))
typs[121] = newSig(params(typs[1], typs[7], typs[22]), nil)
typs[122] = newSig(params(typs[7], typs[22]), nil)
typs[123] = newSig(params(typs[3], typs[3], typs[5]), nil)
typs[124] = newSig(params(typs[7], typs[5]), nil)
typs[125] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6]))
typs[126] = newSig(params(typs[3], typs[3]), params(typs[6]))
typs[127] = newSig(params(typs[7], typs[7]), params(typs[6]))
typs[128] = newSig(params(typs[3], typs[5], typs[5]), params(typs[5]))
typs[129] = newSig(params(typs[7], typs[5]), params(typs[5]))
typs[130] = newSig(params(typs[3], typs[5]), params(typs[5]))
typs[131] = newSig(params(typs[22], typs[22]), params(typs[22]))
typs[132] = newSig(params(typs[24], typs[24]), params(typs[24]))
typs[133] = newSig(params(typs[20]), params(typs[22]))
typs[134] = newSig(params(typs[20]), params(typs[24]))
typs[135] = newSig(params(typs[20]), params(typs[60]))
typs[136] = newSig(params(typs[22]), params(typs[20]))
typs[137] = types.Types[types.TFLOAT32]
typs[138] = newSig(params(typs[22]), params(typs[137]))
typs[139] = newSig(params(typs[24]), params(typs[20]))
typs[140] = newSig(params(typs[24]), params(typs[137]))
typs[141] = newSig(params(typs[60]), params(typs[20]))
typs[142] = newSig(params(typs[26], typs[26]), params(typs[26]))
typs[143] = newSig(nil, params(typs[5]))
typs[144] = newSig(params(typs[5], typs[5]), nil)
typs[145] = newSig(params(typs[5], typs[5], typs[5]), nil)
typs[146] = newSig(params(typs[7], typs[1], typs[5]), nil)
typs[147] = types.NewSlice(typs[7])
typs[148] = newSig(params(typs[7], typs[147]), nil)
typs[149] = newSig(params(typs[64], typs[64], typs[17]), nil)
typs[150] = newSig(params(typs[58], typs[58], typs[17]), nil)
typs[151] = newSig(params(typs[60], typs[60], typs[17]), nil)
typs[152] = newSig(params(typs[24], typs[24], typs[17]), nil)
typs[153] = newSig(params(typs[28], typs[28], typs[17]), nil)
typs[154] = types.NewArray(typs[0], 16)
typs[155] = newSig(params(typs[7], typs[60], typs[154], typs[28], typs[15], typs[64], typs[64]), params(typs[60]))
typs[67] = newSig(params(typs[24]), params(typs[7]))
typs[68] = newSig(params(typs[28]), params(typs[7]))
typs[69] = types.Types[types.TUINT8]
typs[70] = types.NewSlice(typs[69])
typs[71] = newSig(params(typs[70]), params(typs[7]))
typs[72] = newSig(params(typs[1], typs[1]), params(typs[1]))
typs[73] = newSig(params(typs[1], typs[1], typs[1]), nil)
typs[74] = newSig(params(typs[1]), nil)
typs[75] = newSig(params(typs[1], typs[1]), params(typs[15], typs[1]))
typs[76] = types.NewPtr(typs[5])
typs[77] = newSig(params(typs[76], typs[7], typs[7]), params(typs[6]))
typs[78] = newSig(params(typs[15]), nil)
typs[79] = newSig(nil, params(typs[10]))
typs[80] = newSig(nil, params(typs[65]))
typs[81] = types.NewMap(typs[2], typs[2])
typs[82] = newSig(params(typs[1], typs[22], typs[3]), params(typs[81]))
typs[83] = newSig(params(typs[1], typs[15], typs[3]), params(typs[81]))
typs[84] = newSig(nil, params(typs[81]))
typs[85] = newSig(params(typs[1], typs[81], typs[3]), params(typs[3]))
typs[86] = newSig(params(typs[1], typs[81], typs[65]), params(typs[3]))
typs[87] = newSig(params(typs[1], typs[81], typs[24]), params(typs[3]))
typs[88] = newSig(params(typs[1], typs[81], typs[28]), params(typs[3]))
typs[89] = newSig(params(typs[1], typs[81], typs[3], typs[1]), params(typs[3]))
typs[90] = newSig(params(typs[1], typs[81], typs[3]), params(typs[3], typs[6]))
typs[91] = newSig(params(typs[1], typs[81], typs[65]), params(typs[3], typs[6]))
typs[92] = newSig(params(typs[1], typs[81], typs[24]), params(typs[3], typs[6]))
typs[93] = newSig(params(typs[1], typs[81], typs[28]), params(typs[3], typs[6]))
typs[94] = newSig(params(typs[1], typs[81], typs[3], typs[1]), params(typs[3], typs[6]))
typs[95] = newSig(params(typs[1], typs[81], typs[7]), params(typs[3]))
typs[96] = newSig(params(typs[1], typs[81], typs[3]), nil)
typs[97] = newSig(params(typs[1], typs[81], typs[65]), nil)
typs[98] = newSig(params(typs[1], typs[81], typs[24]), nil)
typs[99] = newSig(params(typs[1], typs[81], typs[28]), nil)
typs[100] = newSig(params(typs[3]), nil)
typs[101] = newSig(params(typs[1], typs[81]), nil)
typs[102] = types.NewChan(typs[2], types.Cboth)
typs[103] = newSig(params(typs[1], typs[22]), params(typs[102]))
typs[104] = newSig(params(typs[1], typs[15]), params(typs[102]))
typs[105] = types.NewChan(typs[2], types.Crecv)
typs[106] = newSig(params(typs[105], typs[3]), nil)
typs[107] = newSig(params(typs[105], typs[3]), params(typs[6]))
typs[108] = types.NewChan(typs[2], types.Csend)
typs[109] = newSig(params(typs[108], typs[3]), nil)
typs[110] = newSig(params(typs[108]), nil)
typs[111] = newSig(params(typs[2]), params(typs[15]))
typs[112] = types.NewArray(typs[0], 3)
typs[113] = types.NewStruct([]*types.Field{types.NewField(src.NoXPos, Lookup("enabled"), typs[6]), types.NewField(src.NoXPos, Lookup("pad"), typs[112]), types.NewField(src.NoXPos, Lookup("cgo"), typs[6]), types.NewField(src.NoXPos, Lookup("alignme"), typs[24])})
typs[114] = newSig(params(typs[1], typs[3], typs[3]), nil)
typs[115] = newSig(params(typs[1], typs[3]), nil)
typs[116] = newSig(params(typs[1], typs[3], typs[15], typs[3], typs[15]), params(typs[15]))
typs[117] = newSig(params(typs[108], typs[3]), params(typs[6]))
typs[118] = newSig(params(typs[3], typs[105]), params(typs[6], typs[6]))
typs[119] = newSig(params(typs[76]), nil)
typs[120] = newSig(params(typs[1], typs[1], typs[76], typs[15], typs[15], typs[6]), params(typs[15], typs[6]))
typs[121] = newSig(params(typs[1], typs[15], typs[15]), params(typs[7]))
typs[122] = newSig(params(typs[1], typs[22], typs[22]), params(typs[7]))
typs[123] = newSig(params(typs[1], typs[15], typs[15], typs[7]), params(typs[7]))
typs[124] = types.NewSlice(typs[2])
typs[125] = newSig(params(typs[3], typs[15], typs[15], typs[15], typs[1]), params(typs[124]))
typs[126] = newSig(params(typs[1], typs[7], typs[22]), nil)
typs[127] = newSig(params(typs[7], typs[22]), nil)
typs[128] = newSig(params(typs[3], typs[3], typs[5]), nil)
typs[129] = newSig(params(typs[7], typs[5]), nil)
typs[130] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6]))
typs[131] = newSig(params(typs[3], typs[3]), params(typs[6]))
typs[132] = newSig(params(typs[7], typs[7]), params(typs[6]))
typs[133] = newSig(params(typs[3], typs[5], typs[5]), params(typs[5]))
typs[134] = newSig(params(typs[7], typs[5]), params(typs[5]))
typs[135] = newSig(params(typs[3], typs[5]), params(typs[5]))
typs[136] = newSig(params(typs[22], typs[22]), params(typs[22]))
typs[137] = newSig(params(typs[24], typs[24]), params(typs[24]))
typs[138] = newSig(params(typs[20]), params(typs[22]))
typs[139] = newSig(params(typs[20]), params(typs[24]))
typs[140] = newSig(params(typs[20]), params(typs[65]))
typs[141] = newSig(params(typs[22]), params(typs[20]))
typs[142] = types.Types[types.TFLOAT32]
typs[143] = newSig(params(typs[22]), params(typs[142]))
typs[144] = newSig(params(typs[24]), params(typs[20]))
typs[145] = newSig(params(typs[24]), params(typs[142]))
typs[146] = newSig(params(typs[65]), params(typs[20]))
typs[147] = newSig(params(typs[26], typs[26]), params(typs[26]))
typs[148] = newSig(nil, params(typs[5]))
typs[149] = newSig(params(typs[5], typs[5]), nil)
typs[150] = newSig(params(typs[5], typs[5], typs[5]), nil)
typs[151] = newSig(params(typs[7], typs[1], typs[5]), nil)
typs[152] = types.NewSlice(typs[7])
typs[153] = newSig(params(typs[7], typs[152]), nil)
typs[154] = newSig(params(typs[69], typs[69], typs[17]), nil)
typs[155] = newSig(params(typs[63], typs[63], typs[17]), nil)
typs[156] = newSig(params(typs[65], typs[65], typs[17]), nil)
typs[157] = newSig(params(typs[24], typs[24], typs[17]), nil)
typs[158] = newSig(params(typs[28], typs[28], typs[17]), nil)
typs[159] = types.NewArray(typs[0], 16)
typs[160] = newSig(params(typs[7], typs[65], typs[159], typs[28], typs[15], typs[69], typs[69]), params(typs[65]))
return typs[:]
}

View File

@ -270,6 +270,11 @@ func walkRuneToString(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
// walkStringToBytes walks an OSTR2BYTES node.
func walkStringToBytes(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
s := n.X
if expr, ok := s.(*ir.AddStringExpr); ok {
return walkAddString(n.Type(), expr, init)
}
if ir.IsConst(s, constant.String) {
sc := ir.StringVal(s)

View File

@ -273,7 +273,7 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
return walkNew(n, init)
case ir.OADDSTR:
return walkAddString(n.(*ir.AddStringExpr), init)
return walkAddString(n.Type(), n.(*ir.AddStringExpr), init)
case ir.OAPPEND:
// order should make sure we only see OAS(node, OAPPEND), which we handle above.
@ -464,49 +464,64 @@ func copyExpr(n ir.Node, t *types.Type, init *ir.Nodes) ir.Node {
return l
}
func walkAddString(n *ir.AddStringExpr, init *ir.Nodes) ir.Node {
func walkAddString(typ *types.Type, n *ir.AddStringExpr, init *ir.Nodes) ir.Node {
c := len(n.List)
if c < 2 {
base.Fatalf("walkAddString count %d too small", c)
}
buf := typecheck.NodNil()
if n.Esc() == ir.EscNone {
sz := int64(0)
for _, n1 := range n.List {
if n1.Op() == ir.OLITERAL {
sz += int64(len(ir.StringVal(n1)))
// list of string arguments
var args []ir.Node
var fn, fnsmall, fnbig string
switch {
default:
base.FatalfAt(n.Pos(), "unexpected type: %v", typ)
case typ.IsString():
buf := typecheck.NodNil()
if n.Esc() == ir.EscNone {
sz := int64(0)
for _, n1 := range n.List {
if n1.Op() == ir.OLITERAL {
sz += int64(len(ir.StringVal(n1)))
}
}
// Don't allocate the buffer if the result won't fit.
if sz < tmpstringbufsize {
// Create temporary buffer for result string on stack.
buf = stackBufAddr(tmpstringbufsize, types.Types[types.TUINT8])
}
}
// Don't allocate the buffer if the result won't fit.
if sz < tmpstringbufsize {
// Create temporary buffer for result string on stack.
buf = stackBufAddr(tmpstringbufsize, types.Types[types.TUINT8])
}
args = []ir.Node{buf}
fnsmall, fnbig = "concatstring%d", "concatstrings"
case typ.IsSlice() && typ.Elem().IsKind(types.TUINT8): // Optimize []byte(str1+str2+...)
fnsmall, fnbig = "concatbyte%d", "concatbytes"
}
// build list of string arguments
args := []ir.Node{buf}
for _, n2 := range n.List {
args = append(args, typecheck.Conv(n2, types.Types[types.TSTRING]))
}
var fn string
if c <= 5 {
// small numbers of strings use direct runtime helpers.
// note: order.expr knows this cutoff too.
fn = fmt.Sprintf("concatstring%d", c)
fn = fmt.Sprintf(fnsmall, c)
for _, n2 := range n.List {
args = append(args, typecheck.Conv(n2, types.Types[types.TSTRING]))
}
} else {
// large numbers of strings are passed to the runtime as a slice.
fn = "concatstrings"
fn = fnbig
t := types.NewSlice(types.Types[types.TSTRING])
// args[1:] to skip buf arg
slice := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, t, args[1:])
slargs := make([]ir.Node, len(n.List))
for i, n2 := range n.List {
slargs[i] = typecheck.Conv(n2, types.Types[types.TSTRING])
}
slice := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, t, slargs)
slice.Prealloc = n.Prealloc
args = []ir.Node{buf, slice}
args = append(args, slice)
slice.SetEsc(ir.EscNone)
}
@ -515,7 +530,7 @@ func walkAddString(n *ir.AddStringExpr, init *ir.Nodes) ir.Node {
r.Args = args
r1 := typecheck.Expr(r)
r1 = walkExpr(r1, init)
r1.SetType(n.Type())
r1.SetType(typ)
return r1
}

View File

@ -55,6 +55,11 @@ var builtins = [...]struct {
{"runtime.concatstring4", 1},
{"runtime.concatstring5", 1},
{"runtime.concatstrings", 1},
{"runtime.concatbyte2", 1},
{"runtime.concatbyte3", 1},
{"runtime.concatbyte4", 1},
{"runtime.concatbyte5", 1},
{"runtime.concatbytes", 1},
{"runtime.cmpstring", 1},
{"runtime.intstring", 1},
{"runtime.slicebytetostring", 1},

View File

@ -72,6 +72,49 @@ func concatstring5(buf *tmpBuf, a0, a1, a2, a3, a4 string) string {
return concatstrings(buf, []string{a0, a1, a2, a3, a4})
}
// concatbytes implements a Go string concatenation x+y+z+... returning a slice
// of bytes.
// The operands are passed in the slice a.
func concatbytes(a []string) []byte {
l := 0
for _, x := range a {
n := len(x)
if l+n < l {
throw("string concatenation too long")
}
l += n
}
if l == 0 {
// This is to match the return type of the non-optimized concatenation.
return []byte{}
}
b := rawbyteslice(l)
offset := 0
for _, x := range a {
copy(b[offset:], x)
offset += len(x)
}
return b
}
func concatbyte2(a0, a1 string) []byte {
return concatbytes([]string{a0, a1})
}
func concatbyte3(a0, a1, a2 string) []byte {
return concatbytes([]string{a0, a1, a2})
}
func concatbyte4(a0, a1, a2, a3 string) []byte {
return concatbytes([]string{a0, a1, a2, a3})
}
func concatbyte5(a0, a1, a2, a3, a4 string) []byte {
return concatbytes([]string{a0, a1, a2, a3, a4})
}
// slicebytetostring converts a byte slice to a string.
// It is inserted by the compiler into generated code.
// ptr is a pointer to the first element of the slice;

View File

@ -26,6 +26,11 @@ func ToByteSlice() []byte { // Issue #24698
return []byte("foo")
}
func ConvertToByteSlice(a, b, c string) []byte {
// amd64:`.*runtime.concatbyte3`
return []byte(a + b + c)
}
// Loading from read-only symbols should get transformed into constants.
func ConstantLoad() {
// 12592 = 0x3130