cmd/compile: optimize make+copy pattern to avoid memclr

match:
 m = make([]T, x); copy(m, s)
for pointer free T and x==len(s) rewrite to:
 m = mallocgc(x*elemsize(T), nil, false); memmove(&m, &s, x*elemsize(T))
otherwise rewrite to:
 m = makeslicecopy([]T, x, s)

This avoids memclear and shading of pointers in the newly created slice
before the copy.

With this CL "s" is only be allowed to bev a variable and not a more
complex expression. This restriction could be lifted in future versions
of this optimization when it can be proven that "s" is not referencing "m".

Triggers 450 times during make.bash..
Reduces go binary size by ~8 kbyte.

name                           old time/op  new time/op  delta
MakeSliceCopy/mallocmove/Byte  71.1ns ± 1%  65.8ns ± 0%  -7.49%  (p=0.000 n=10+9)
MakeSliceCopy/mallocmove/Int   71.2ns ± 1%  66.0ns ± 0%  -7.27%  (p=0.000 n=10+8)
MakeSliceCopy/mallocmove/Ptr    104ns ± 4%    99ns ± 1%  -5.13%  (p=0.000 n=10+10)
MakeSliceCopy/makecopy/Byte    70.3ns ± 0%  68.0ns ± 0%  -3.22%  (p=0.000 n=10+9)
MakeSliceCopy/makecopy/Int     70.3ns ± 0%  68.5ns ± 1%  -2.59%  (p=0.000 n=9+10)
MakeSliceCopy/makecopy/Ptr      102ns ± 0%    99ns ± 1%  -2.97%  (p=0.000 n=9+9)
MakeSliceCopy/nilappend/Byte   75.4ns ± 0%  74.9ns ± 2%  -0.63%  (p=0.015 n=9+9)
MakeSliceCopy/nilappend/Int    75.6ns ± 0%  76.4ns ± 3%    ~     (p=0.245 n=9+10)
MakeSliceCopy/nilappend/Ptr     107ns ± 0%   108ns ± 1%  +0.93%  (p=0.005 n=9+10)

Fixes #26252

Change-Id: Iec553dd1fef6ded16197216a472351c8799a8e71
Reviewed-on: https://go-review.googlesource.com/c/go/+/146719
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Martin Möhrmann <moehrmann@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Martin Möhrmann 2018-10-23 13:50:07 +02:00
parent 97240d546c
commit 6ed4661807
12 changed files with 1160 additions and 503 deletions

View File

@ -10,325 +10,329 @@ var runtimeDecls = [...]struct {
typ int typ int
}{ }{
{"newobject", funcTag, 4}, {"newobject", funcTag, 4},
{"panicdivide", funcTag, 5}, {"mallocgc", funcTag, 8},
{"panicshift", funcTag, 5}, {"panicdivide", funcTag, 9},
{"panicmakeslicelen", funcTag, 5}, {"panicshift", funcTag, 9},
{"panicmakeslicecap", funcTag, 5}, {"panicmakeslicelen", funcTag, 9},
{"throwinit", funcTag, 5}, {"panicmakeslicecap", funcTag, 9},
{"panicwrap", funcTag, 5}, {"throwinit", funcTag, 9},
{"gopanic", funcTag, 7}, {"panicwrap", funcTag, 9},
{"gorecover", funcTag, 10}, {"gopanic", funcTag, 11},
{"goschedguarded", funcTag, 5}, {"gorecover", funcTag, 14},
{"goPanicIndex", funcTag, 12}, {"goschedguarded", funcTag, 9},
{"goPanicIndexU", funcTag, 14}, {"goPanicIndex", funcTag, 16},
{"goPanicSliceAlen", funcTag, 12}, {"goPanicIndexU", funcTag, 18},
{"goPanicSliceAlenU", funcTag, 14}, {"goPanicSliceAlen", funcTag, 16},
{"goPanicSliceAcap", funcTag, 12}, {"goPanicSliceAlenU", funcTag, 18},
{"goPanicSliceAcapU", funcTag, 14}, {"goPanicSliceAcap", funcTag, 16},
{"goPanicSliceB", funcTag, 12}, {"goPanicSliceAcapU", funcTag, 18},
{"goPanicSliceBU", funcTag, 14}, {"goPanicSliceB", funcTag, 16},
{"goPanicSlice3Alen", funcTag, 12}, {"goPanicSliceBU", funcTag, 18},
{"goPanicSlice3AlenU", funcTag, 14}, {"goPanicSlice3Alen", funcTag, 16},
{"goPanicSlice3Acap", funcTag, 12}, {"goPanicSlice3AlenU", funcTag, 18},
{"goPanicSlice3AcapU", funcTag, 14}, {"goPanicSlice3Acap", funcTag, 16},
{"goPanicSlice3B", funcTag, 12}, {"goPanicSlice3AcapU", funcTag, 18},
{"goPanicSlice3BU", funcTag, 14}, {"goPanicSlice3B", funcTag, 16},
{"goPanicSlice3C", funcTag, 12}, {"goPanicSlice3BU", funcTag, 18},
{"goPanicSlice3CU", funcTag, 14}, {"goPanicSlice3C", funcTag, 16},
{"printbool", funcTag, 16}, {"goPanicSlice3CU", funcTag, 18},
{"printfloat", funcTag, 18}, {"printbool", funcTag, 19},
{"printint", funcTag, 20}, {"printfloat", funcTag, 21},
{"printhex", funcTag, 22}, {"printint", funcTag, 23},
{"printuint", funcTag, 22}, {"printhex", funcTag, 25},
{"printcomplex", funcTag, 24}, {"printuint", funcTag, 25},
{"printstring", funcTag, 26}, {"printcomplex", funcTag, 27},
{"printpointer", funcTag, 27}, {"printstring", funcTag, 29},
{"printiface", funcTag, 27}, {"printpointer", funcTag, 30},
{"printeface", funcTag, 27}, {"printiface", funcTag, 30},
{"printslice", funcTag, 27}, {"printeface", funcTag, 30},
{"printnl", funcTag, 5}, {"printslice", funcTag, 30},
{"printsp", funcTag, 5}, {"printnl", funcTag, 9},
{"printlock", funcTag, 5}, {"printsp", funcTag, 9},
{"printunlock", funcTag, 5}, {"printlock", funcTag, 9},
{"concatstring2", funcTag, 30}, {"printunlock", funcTag, 9},
{"concatstring3", funcTag, 31}, {"concatstring2", funcTag, 33},
{"concatstring4", funcTag, 32}, {"concatstring3", funcTag, 34},
{"concatstring5", funcTag, 33}, {"concatstring4", funcTag, 35},
{"concatstrings", funcTag, 35}, {"concatstring5", funcTag, 36},
{"cmpstring", funcTag, 36}, {"concatstrings", funcTag, 38},
{"intstring", funcTag, 39}, {"cmpstring", funcTag, 39},
{"slicebytetostring", funcTag, 40}, {"intstring", funcTag, 42},
{"slicebytetostringtmp", funcTag, 41}, {"slicebytetostring", funcTag, 43},
{"slicerunetostring", funcTag, 44}, {"slicebytetostringtmp", funcTag, 44},
{"stringtoslicebyte", funcTag, 46}, {"slicerunetostring", funcTag, 47},
{"stringtoslicerune", funcTag, 49}, {"stringtoslicebyte", funcTag, 49},
{"slicecopy", funcTag, 51}, {"stringtoslicerune", funcTag, 52},
{"slicestringcopy", funcTag, 52}, {"slicecopy", funcTag, 53},
{"decoderune", funcTag, 53}, {"slicestringcopy", funcTag, 54},
{"countrunes", funcTag, 54}, {"decoderune", funcTag, 55},
{"convI2I", funcTag, 55}, {"countrunes", funcTag, 56},
{"convT16", funcTag, 57}, {"convI2I", funcTag, 57},
{"convT32", funcTag, 57}, {"convT16", funcTag, 58},
{"convT64", funcTag, 57}, {"convT32", funcTag, 58},
{"convTstring", funcTag, 57}, {"convT64", funcTag, 58},
{"convTslice", funcTag, 57}, {"convTstring", funcTag, 58},
{"convT2E", funcTag, 58}, {"convTslice", funcTag, 58},
{"convT2Enoptr", funcTag, 58}, {"convT2E", funcTag, 59},
{"convT2I", funcTag, 58}, {"convT2Enoptr", funcTag, 59},
{"convT2Inoptr", funcTag, 58}, {"convT2I", funcTag, 59},
{"assertE2I", funcTag, 55}, {"convT2Inoptr", funcTag, 59},
{"assertE2I2", funcTag, 59}, {"assertE2I", funcTag, 57},
{"assertI2I", funcTag, 55}, {"assertE2I2", funcTag, 60},
{"assertI2I2", funcTag, 59}, {"assertI2I", funcTag, 57},
{"panicdottypeE", funcTag, 60}, {"assertI2I2", funcTag, 60},
{"panicdottypeI", funcTag, 60}, {"panicdottypeE", funcTag, 61},
{"panicnildottype", funcTag, 61}, {"panicdottypeI", funcTag, 61},
{"ifaceeq", funcTag, 63}, {"panicnildottype", funcTag, 62},
{"efaceeq", funcTag, 63}, {"ifaceeq", funcTag, 64},
{"fastrand", funcTag, 65}, {"efaceeq", funcTag, 64},
{"makemap64", funcTag, 67}, {"fastrand", funcTag, 66},
{"makemap", funcTag, 68}, {"makemap64", funcTag, 68},
{"makemap_small", funcTag, 69}, {"makemap", funcTag, 69},
{"mapaccess1", funcTag, 70}, {"makemap_small", funcTag, 70},
{"mapaccess1_fast32", funcTag, 71}, {"mapaccess1", funcTag, 71},
{"mapaccess1_fast64", funcTag, 71}, {"mapaccess1_fast32", funcTag, 72},
{"mapaccess1_faststr", funcTag, 71}, {"mapaccess1_fast64", funcTag, 72},
{"mapaccess1_fat", funcTag, 72}, {"mapaccess1_faststr", funcTag, 72},
{"mapaccess2", funcTag, 73}, {"mapaccess1_fat", funcTag, 73},
{"mapaccess2_fast32", funcTag, 74}, {"mapaccess2", funcTag, 74},
{"mapaccess2_fast64", funcTag, 74}, {"mapaccess2_fast32", funcTag, 75},
{"mapaccess2_faststr", funcTag, 74}, {"mapaccess2_fast64", funcTag, 75},
{"mapaccess2_fat", funcTag, 75}, {"mapaccess2_faststr", funcTag, 75},
{"mapassign", funcTag, 70}, {"mapaccess2_fat", funcTag, 76},
{"mapassign_fast32", funcTag, 71}, {"mapassign", funcTag, 71},
{"mapassign_fast32ptr", funcTag, 71}, {"mapassign_fast32", funcTag, 72},
{"mapassign_fast64", funcTag, 71}, {"mapassign_fast32ptr", funcTag, 72},
{"mapassign_fast64ptr", funcTag, 71}, {"mapassign_fast64", funcTag, 72},
{"mapassign_faststr", funcTag, 71}, {"mapassign_fast64ptr", funcTag, 72},
{"mapiterinit", funcTag, 76}, {"mapassign_faststr", funcTag, 72},
{"mapdelete", funcTag, 76}, {"mapiterinit", funcTag, 77},
{"mapdelete_fast32", funcTag, 77}, {"mapdelete", funcTag, 77},
{"mapdelete_fast64", funcTag, 77}, {"mapdelete_fast32", funcTag, 78},
{"mapdelete_faststr", funcTag, 77}, {"mapdelete_fast64", funcTag, 78},
{"mapiternext", funcTag, 78}, {"mapdelete_faststr", funcTag, 78},
{"mapclear", funcTag, 79}, {"mapiternext", funcTag, 79},
{"makechan64", funcTag, 81}, {"mapclear", funcTag, 80},
{"makechan", funcTag, 82}, {"makechan64", funcTag, 82},
{"chanrecv1", funcTag, 84}, {"makechan", funcTag, 83},
{"chanrecv2", funcTag, 85}, {"chanrecv1", funcTag, 85},
{"chansend1", funcTag, 87}, {"chanrecv2", funcTag, 86},
{"closechan", funcTag, 27}, {"chansend1", funcTag, 88},
{"writeBarrier", varTag, 89}, {"closechan", funcTag, 30},
{"typedmemmove", funcTag, 90}, {"writeBarrier", varTag, 90},
{"typedmemclr", funcTag, 91}, {"typedmemmove", funcTag, 91},
{"typedslicecopy", funcTag, 92}, {"typedmemclr", funcTag, 92},
{"selectnbsend", funcTag, 93}, {"typedslicecopy", funcTag, 93},
{"selectnbrecv", funcTag, 94}, {"selectnbsend", funcTag, 94},
{"selectnbrecv2", funcTag, 96}, {"selectnbrecv", funcTag, 95},
{"selectsetpc", funcTag, 61}, {"selectnbrecv2", funcTag, 97},
{"selectgo", funcTag, 97}, {"selectsetpc", funcTag, 62},
{"block", funcTag, 5}, {"selectgo", funcTag, 98},
{"makeslice", funcTag, 98}, {"block", funcTag, 9},
{"makeslice64", funcTag, 99}, {"makeslice", funcTag, 99},
{"growslice", funcTag, 101}, {"makeslice64", funcTag, 100},
{"memmove", funcTag, 102}, {"makeslicecopy", funcTag, 101},
{"memclrNoHeapPointers", funcTag, 103}, {"growslice", funcTag, 103},
{"memclrHasPointers", funcTag, 103}, {"memmove", funcTag, 104},
{"memequal", funcTag, 104}, {"memclrNoHeapPointers", funcTag, 105},
{"memequal0", funcTag, 105}, {"memclrHasPointers", funcTag, 105},
{"memequal8", funcTag, 105}, {"memequal", funcTag, 106},
{"memequal16", funcTag, 105}, {"memequal0", funcTag, 107},
{"memequal32", funcTag, 105}, {"memequal8", funcTag, 107},
{"memequal64", funcTag, 105}, {"memequal16", funcTag, 107},
{"memequal128", funcTag, 105}, {"memequal32", funcTag, 107},
{"f32equal", funcTag, 106}, {"memequal64", funcTag, 107},
{"f64equal", funcTag, 106}, {"memequal128", funcTag, 107},
{"c64equal", funcTag, 106}, {"f32equal", funcTag, 108},
{"c128equal", funcTag, 106}, {"f64equal", funcTag, 108},
{"strequal", funcTag, 106}, {"c64equal", funcTag, 108},
{"interequal", funcTag, 106}, {"c128equal", funcTag, 108},
{"nilinterequal", funcTag, 106}, {"strequal", funcTag, 108},
{"memhash", funcTag, 107}, {"interequal", funcTag, 108},
{"memhash0", funcTag, 108}, {"nilinterequal", funcTag, 108},
{"memhash8", funcTag, 108}, {"memhash", funcTag, 109},
{"memhash16", funcTag, 108}, {"memhash0", funcTag, 110},
{"memhash32", funcTag, 108}, {"memhash8", funcTag, 110},
{"memhash64", funcTag, 108}, {"memhash16", funcTag, 110},
{"memhash128", funcTag, 108}, {"memhash32", funcTag, 110},
{"f32hash", funcTag, 108}, {"memhash64", funcTag, 110},
{"f64hash", funcTag, 108}, {"memhash128", funcTag, 110},
{"c64hash", funcTag, 108}, {"f32hash", funcTag, 110},
{"c128hash", funcTag, 108}, {"f64hash", funcTag, 110},
{"strhash", funcTag, 108}, {"c64hash", funcTag, 110},
{"interhash", funcTag, 108}, {"c128hash", funcTag, 110},
{"nilinterhash", funcTag, 108}, {"strhash", funcTag, 110},
{"int64div", funcTag, 109}, {"interhash", funcTag, 110},
{"uint64div", funcTag, 110}, {"nilinterhash", funcTag, 110},
{"int64mod", funcTag, 109}, {"int64div", funcTag, 111},
{"uint64mod", funcTag, 110}, {"uint64div", funcTag, 112},
{"float64toint64", funcTag, 111}, {"int64mod", funcTag, 111},
{"float64touint64", funcTag, 112}, {"uint64mod", funcTag, 112},
{"float64touint32", funcTag, 113}, {"float64toint64", funcTag, 113},
{"int64tofloat64", funcTag, 114}, {"float64touint64", funcTag, 114},
{"uint64tofloat64", funcTag, 115}, {"float64touint32", funcTag, 115},
{"uint32tofloat64", funcTag, 116}, {"int64tofloat64", funcTag, 116},
{"complex128div", funcTag, 117}, {"uint64tofloat64", funcTag, 117},
{"racefuncenter", funcTag, 118}, {"uint32tofloat64", funcTag, 118},
{"racefuncenterfp", funcTag, 5}, {"complex128div", funcTag, 119},
{"racefuncexit", funcTag, 5}, {"racefuncenter", funcTag, 120},
{"raceread", funcTag, 118}, {"racefuncenterfp", funcTag, 9},
{"racewrite", funcTag, 118}, {"racefuncexit", funcTag, 9},
{"racereadrange", funcTag, 119}, {"raceread", funcTag, 120},
{"racewriterange", funcTag, 119}, {"racewrite", funcTag, 120},
{"msanread", funcTag, 119}, {"racereadrange", funcTag, 121},
{"msanwrite", funcTag, 119}, {"racewriterange", funcTag, 121},
{"checkptrAlignment", funcTag, 120}, {"msanread", funcTag, 121},
{"checkptrArithmetic", funcTag, 122}, {"msanwrite", funcTag, 121},
{"libfuzzerTraceCmp1", funcTag, 124}, {"checkptrAlignment", funcTag, 122},
{"libfuzzerTraceCmp2", funcTag, 126}, {"checkptrArithmetic", funcTag, 124},
{"libfuzzerTraceCmp4", funcTag, 127}, {"libfuzzerTraceCmp1", funcTag, 126},
{"libfuzzerTraceCmp8", funcTag, 128}, {"libfuzzerTraceCmp2", funcTag, 128},
{"libfuzzerTraceConstCmp1", funcTag, 124}, {"libfuzzerTraceCmp4", funcTag, 129},
{"libfuzzerTraceConstCmp2", funcTag, 126}, {"libfuzzerTraceCmp8", funcTag, 130},
{"libfuzzerTraceConstCmp4", funcTag, 127}, {"libfuzzerTraceConstCmp1", funcTag, 126},
{"libfuzzerTraceConstCmp8", funcTag, 128}, {"libfuzzerTraceConstCmp2", funcTag, 128},
{"x86HasPOPCNT", varTag, 15}, {"libfuzzerTraceConstCmp4", funcTag, 129},
{"x86HasSSE41", varTag, 15}, {"libfuzzerTraceConstCmp8", funcTag, 130},
{"x86HasFMA", varTag, 15}, {"x86HasPOPCNT", varTag, 6},
{"armHasVFPv4", varTag, 15}, {"x86HasSSE41", varTag, 6},
{"arm64HasATOMICS", varTag, 15}, {"x86HasFMA", varTag, 6},
{"armHasVFPv4", varTag, 6},
{"arm64HasATOMICS", varTag, 6},
} }
func runtimeTypes() []*types.Type { func runtimeTypes() []*types.Type {
var typs [129]*types.Type var typs [131]*types.Type
typs[0] = types.Bytetype typs[0] = types.Bytetype
typs[1] = types.NewPtr(typs[0]) typs[1] = types.NewPtr(typs[0])
typs[2] = types.Types[TANY] typs[2] = types.Types[TANY]
typs[3] = types.NewPtr(typs[2]) typs[3] = types.NewPtr(typs[2])
typs[4] = functype(nil, []*Node{anonfield(typs[1])}, []*Node{anonfield(typs[3])}) typs[4] = functype(nil, []*Node{anonfield(typs[1])}, []*Node{anonfield(typs[3])})
typs[5] = functype(nil, nil, nil) typs[5] = types.Types[TUINTPTR]
typs[6] = types.Types[TINTER] typs[6] = types.Types[TBOOL]
typs[7] = functype(nil, []*Node{anonfield(typs[6])}, nil) typs[7] = types.Types[TUNSAFEPTR]
typs[8] = types.Types[TINT32] typs[8] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[1]), anonfield(typs[6])}, []*Node{anonfield(typs[7])})
typs[9] = types.NewPtr(typs[8]) typs[9] = functype(nil, nil, nil)
typs[10] = functype(nil, []*Node{anonfield(typs[9])}, []*Node{anonfield(typs[6])}) typs[10] = types.Types[TINTER]
typs[11] = types.Types[TINT] typs[11] = functype(nil, []*Node{anonfield(typs[10])}, nil)
typs[12] = functype(nil, []*Node{anonfield(typs[11]), anonfield(typs[11])}, nil) typs[12] = types.Types[TINT32]
typs[13] = types.Types[TUINT] typs[13] = types.NewPtr(typs[12])
typs[14] = functype(nil, []*Node{anonfield(typs[13]), anonfield(typs[11])}, nil) typs[14] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[10])})
typs[15] = types.Types[TBOOL] typs[15] = types.Types[TINT]
typs[16] = functype(nil, []*Node{anonfield(typs[15])}, nil) typs[16] = functype(nil, []*Node{anonfield(typs[15]), anonfield(typs[15])}, nil)
typs[17] = types.Types[TFLOAT64] typs[17] = types.Types[TUINT]
typs[18] = functype(nil, []*Node{anonfield(typs[17])}, nil) typs[18] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[15])}, nil)
typs[19] = types.Types[TINT64] typs[19] = functype(nil, []*Node{anonfield(typs[6])}, nil)
typs[20] = functype(nil, []*Node{anonfield(typs[19])}, nil) typs[20] = types.Types[TFLOAT64]
typs[21] = types.Types[TUINT64] typs[21] = functype(nil, []*Node{anonfield(typs[20])}, nil)
typs[22] = functype(nil, []*Node{anonfield(typs[21])}, nil) typs[22] = types.Types[TINT64]
typs[23] = types.Types[TCOMPLEX128] typs[23] = functype(nil, []*Node{anonfield(typs[22])}, nil)
typs[24] = functype(nil, []*Node{anonfield(typs[23])}, nil) typs[24] = types.Types[TUINT64]
typs[25] = types.Types[TSTRING] typs[25] = functype(nil, []*Node{anonfield(typs[24])}, nil)
typs[26] = functype(nil, []*Node{anonfield(typs[25])}, nil) typs[26] = types.Types[TCOMPLEX128]
typs[27] = functype(nil, []*Node{anonfield(typs[2])}, nil) typs[27] = functype(nil, []*Node{anonfield(typs[26])}, nil)
typs[28] = types.NewArray(typs[0], 32) typs[28] = types.Types[TSTRING]
typs[29] = types.NewPtr(typs[28]) typs[29] = functype(nil, []*Node{anonfield(typs[28])}, nil)
typs[30] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[25])}) typs[30] = functype(nil, []*Node{anonfield(typs[2])}, nil)
typs[31] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[25])}) typs[31] = types.NewArray(typs[0], 32)
typs[32] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[25])}) typs[32] = types.NewPtr(typs[31])
typs[33] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[25])}) typs[33] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
typs[34] = types.NewSlice(typs[25]) typs[34] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
typs[35] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[34])}, []*Node{anonfield(typs[25])}) typs[35] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
typs[36] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[11])}) typs[36] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
typs[37] = types.NewArray(typs[0], 4) typs[37] = types.NewSlice(typs[28])
typs[38] = types.NewPtr(typs[37]) typs[38] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[37])}, []*Node{anonfield(typs[28])})
typs[39] = functype(nil, []*Node{anonfield(typs[38]), anonfield(typs[19])}, []*Node{anonfield(typs[25])}) typs[39] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[15])})
typs[40] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[25])}) typs[40] = types.NewArray(typs[0], 4)
typs[41] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[25])}) typs[41] = types.NewPtr(typs[40])
typs[42] = types.Runetype typs[42] = functype(nil, []*Node{anonfield(typs[41]), anonfield(typs[22])}, []*Node{anonfield(typs[28])})
typs[43] = types.NewSlice(typs[42]) typs[43] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
typs[44] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[43])}, []*Node{anonfield(typs[25])}) typs[44] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
typs[45] = types.NewSlice(typs[0]) typs[45] = types.Runetype
typs[46] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25])}, []*Node{anonfield(typs[45])}) typs[46] = types.NewSlice(typs[45])
typs[47] = types.NewArray(typs[42], 32) typs[47] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[46])}, []*Node{anonfield(typs[28])})
typs[48] = types.NewPtr(typs[47]) typs[48] = types.NewSlice(typs[0])
typs[49] = functype(nil, []*Node{anonfield(typs[48]), anonfield(typs[25])}, []*Node{anonfield(typs[43])}) typs[49] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28])}, []*Node{anonfield(typs[48])})
typs[50] = types.Types[TUINTPTR] typs[50] = types.NewArray(typs[45], 32)
typs[51] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[11]), anonfield(typs[3]), anonfield(typs[11]), anonfield(typs[50])}, []*Node{anonfield(typs[11])}) typs[51] = types.NewPtr(typs[50])
typs[52] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11]), anonfield(typs[25])}, []*Node{anonfield(typs[11])}) typs[52] = functype(nil, []*Node{anonfield(typs[51]), anonfield(typs[28])}, []*Node{anonfield(typs[46])})
typs[53] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[11])}, []*Node{anonfield(typs[42]), anonfield(typs[11])}) typs[53] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[5])}, []*Node{anonfield(typs[15])})
typs[54] = functype(nil, []*Node{anonfield(typs[25])}, []*Node{anonfield(typs[11])}) typs[54] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[28])}, []*Node{anonfield(typs[15])})
typs[55] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])}) typs[55] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[15])}, []*Node{anonfield(typs[45]), anonfield(typs[15])})
typs[56] = types.Types[TUNSAFEPTR] typs[56] = functype(nil, []*Node{anonfield(typs[28])}, []*Node{anonfield(typs[15])})
typs[57] = functype(nil, []*Node{anonfield(typs[2])}, []*Node{anonfield(typs[56])}) typs[57] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
typs[58] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])}) typs[58] = functype(nil, []*Node{anonfield(typs[2])}, []*Node{anonfield(typs[7])})
typs[59] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[15])}) typs[59] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])})
typs[60] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil) typs[60] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[6])})
typs[61] = functype(nil, []*Node{anonfield(typs[1])}, nil) typs[61] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
typs[62] = types.NewPtr(typs[50]) typs[62] = functype(nil, []*Node{anonfield(typs[1])}, nil)
typs[63] = functype(nil, []*Node{anonfield(typs[62]), anonfield(typs[56]), anonfield(typs[56])}, []*Node{anonfield(typs[15])}) typs[63] = types.NewPtr(typs[5])
typs[64] = types.Types[TUINT32] typs[64] = functype(nil, []*Node{anonfield(typs[63]), anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
typs[65] = functype(nil, nil, []*Node{anonfield(typs[64])}) typs[65] = types.Types[TUINT32]
typs[66] = types.NewMap(typs[2], typs[2]) typs[66] = functype(nil, nil, []*Node{anonfield(typs[65])})
typs[67] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[19]), anonfield(typs[3])}, []*Node{anonfield(typs[66])}) typs[67] = types.NewMap(typs[2], typs[2])
typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11]), anonfield(typs[3])}, []*Node{anonfield(typs[66])}) typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[3])}, []*Node{anonfield(typs[67])})
typs[69] = functype(nil, nil, []*Node{anonfield(typs[66])}) typs[69] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*Node{anonfield(typs[67])})
typs[70] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, []*Node{anonfield(typs[3])}) typs[70] = functype(nil, nil, []*Node{anonfield(typs[67])})
typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, []*Node{anonfield(typs[3])}) typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*Node{anonfield(typs[3])})
typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])}) typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*Node{anonfield(typs[3])})
typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[15])}) typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])})
typs[74] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[15])}) typs[74] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
typs[75] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[15])}) typs[75] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
typs[76] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, nil) typs[76] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
typs[77] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, nil) typs[77] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, nil)
typs[78] = functype(nil, []*Node{anonfield(typs[3])}, nil) typs[78] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, nil)
typs[79] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66])}, nil) typs[79] = functype(nil, []*Node{anonfield(typs[3])}, nil)
typs[80] = types.NewChan(typs[2], types.Cboth) typs[80] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67])}, nil)
typs[81] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[19])}, []*Node{anonfield(typs[80])}) typs[81] = types.NewChan(typs[2], types.Cboth)
typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[80])}) typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22])}, []*Node{anonfield(typs[81])})
typs[83] = types.NewChan(typs[2], types.Crecv) typs[83] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[81])})
typs[84] = functype(nil, []*Node{anonfield(typs[83]), anonfield(typs[3])}, nil) typs[84] = types.NewChan(typs[2], types.Crecv)
typs[85] = functype(nil, []*Node{anonfield(typs[83]), anonfield(typs[3])}, []*Node{anonfield(typs[15])}) typs[85] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, nil)
typs[86] = types.NewChan(typs[2], types.Csend) typs[86] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
typs[87] = functype(nil, []*Node{anonfield(typs[86]), anonfield(typs[3])}, nil) typs[87] = types.NewChan(typs[2], types.Csend)
typs[88] = types.NewArray(typs[0], 3) typs[88] = functype(nil, []*Node{anonfield(typs[87]), anonfield(typs[3])}, nil)
typs[89] = tostruct([]*Node{namedfield("enabled", typs[15]), namedfield("pad", typs[88]), namedfield("needed", typs[15]), namedfield("cgo", typs[15]), namedfield("alignme", typs[21])}) typs[89] = types.NewArray(typs[0], 3)
typs[90] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil) typs[90] = tostruct([]*Node{namedfield("enabled", typs[6]), namedfield("pad", typs[89]), namedfield("needed", typs[6]), namedfield("cgo", typs[6]), namedfield("alignme", typs[24])})
typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil) typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[11]), anonfield(typs[3]), anonfield(typs[11])}, []*Node{anonfield(typs[11])}) typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
typs[93] = functype(nil, []*Node{anonfield(typs[86]), anonfield(typs[3])}, []*Node{anonfield(typs[15])}) typs[93] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15])}, []*Node{anonfield(typs[15])})
typs[94] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[83])}, []*Node{anonfield(typs[15])}) typs[94] = functype(nil, []*Node{anonfield(typs[87]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
typs[95] = types.NewPtr(typs[15]) typs[95] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
typs[96] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[95]), anonfield(typs[83])}, []*Node{anonfield(typs[15])}) typs[96] = types.NewPtr(typs[6])
typs[97] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[11]), anonfield(typs[15])}) typs[97] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[96]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
typs[98] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11]), anonfield(typs[11])}, []*Node{anonfield(typs[56])}) typs[98] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[15]), anonfield(typs[6])})
typs[99] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[56])}) typs[99] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[7])})
typs[100] = types.NewSlice(typs[2]) typs[100] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[7])})
typs[101] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[100]), anonfield(typs[11])}, []*Node{anonfield(typs[100])}) typs[101] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[7])}, []*Node{anonfield(typs[7])})
typs[102] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[50])}, nil) typs[102] = types.NewSlice(typs[2])
typs[103] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[50])}, nil) typs[103] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[102]), anonfield(typs[15])}, []*Node{anonfield(typs[102])})
typs[104] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[50])}, []*Node{anonfield(typs[15])}) typs[104] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, nil)
typs[105] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[15])}) typs[105] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, nil)
typs[106] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[56])}, []*Node{anonfield(typs[15])}) typs[106] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, []*Node{anonfield(typs[6])})
typs[107] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[50]), anonfield(typs[50])}, []*Node{anonfield(typs[50])}) typs[107] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
typs[108] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[50])}, []*Node{anonfield(typs[50])}) typs[108] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
typs[109] = functype(nil, []*Node{anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[19])}) typs[109] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
typs[110] = functype(nil, []*Node{anonfield(typs[21]), anonfield(typs[21])}, []*Node{anonfield(typs[21])}) typs[110] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
typs[111] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[19])}) typs[111] = functype(nil, []*Node{anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[22])})
typs[112] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[21])}) typs[112] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, []*Node{anonfield(typs[24])})
typs[113] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[64])}) typs[113] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[22])})
typs[114] = functype(nil, []*Node{anonfield(typs[19])}, []*Node{anonfield(typs[17])}) typs[114] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[24])})
typs[115] = functype(nil, []*Node{anonfield(typs[21])}, []*Node{anonfield(typs[17])}) typs[115] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[65])})
typs[116] = functype(nil, []*Node{anonfield(typs[64])}, []*Node{anonfield(typs[17])}) typs[116] = functype(nil, []*Node{anonfield(typs[22])}, []*Node{anonfield(typs[20])})
typs[117] = functype(nil, []*Node{anonfield(typs[23]), anonfield(typs[23])}, []*Node{anonfield(typs[23])}) typs[117] = functype(nil, []*Node{anonfield(typs[24])}, []*Node{anonfield(typs[20])})
typs[118] = functype(nil, []*Node{anonfield(typs[50])}, nil) typs[118] = functype(nil, []*Node{anonfield(typs[65])}, []*Node{anonfield(typs[20])})
typs[119] = functype(nil, []*Node{anonfield(typs[50]), anonfield(typs[50])}, nil) typs[119] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[26])}, []*Node{anonfield(typs[26])})
typs[120] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[1]), anonfield(typs[50])}, nil) typs[120] = functype(nil, []*Node{anonfield(typs[5])}, nil)
typs[121] = types.NewSlice(typs[56]) typs[121] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[5])}, nil)
typs[122] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[121])}, nil) typs[122] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[1]), anonfield(typs[5])}, nil)
typs[123] = types.Types[TUINT8] typs[123] = types.NewSlice(typs[7])
typs[124] = functype(nil, []*Node{anonfield(typs[123]), anonfield(typs[123])}, nil) typs[124] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[123])}, nil)
typs[125] = types.Types[TUINT16] typs[125] = types.Types[TUINT8]
typs[126] = functype(nil, []*Node{anonfield(typs[125]), anonfield(typs[125])}, nil) typs[126] = functype(nil, []*Node{anonfield(typs[125]), anonfield(typs[125])}, nil)
typs[127] = functype(nil, []*Node{anonfield(typs[64]), anonfield(typs[64])}, nil) typs[127] = types.Types[TUINT16]
typs[128] = functype(nil, []*Node{anonfield(typs[21]), anonfield(typs[21])}, nil) typs[128] = functype(nil, []*Node{anonfield(typs[127]), anonfield(typs[127])}, nil)
typs[129] = functype(nil, []*Node{anonfield(typs[65]), anonfield(typs[65])}, nil)
typs[130] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, nil)
return typs[:] return typs[:]
} }

View File

@ -15,6 +15,7 @@ package runtime
import "unsafe" import "unsafe"
func newobject(typ *byte) *any func newobject(typ *byte) *any
func mallocgc(size uintptr, typ *byte, needszero bool) unsafe.Pointer
func panicdivide() func panicdivide()
func panicshift() func panicshift()
func panicmakeslicelen() func panicmakeslicelen()
@ -174,6 +175,7 @@ func block()
func makeslice(typ *byte, len int, cap int) unsafe.Pointer func makeslice(typ *byte, len int, cap int) unsafe.Pointer
func makeslice64(typ *byte, len int64, cap int64) unsafe.Pointer func makeslice64(typ *byte, len int64, cap int64) unsafe.Pointer
func makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer
func growslice(typ *byte, old []any, cap int) (ary []any) func growslice(typ *byte, old []any, cap int) (ary []any)
func memmove(to *any, frm *any, length uintptr) func memmove(to *any, frm *any, length uintptr)
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr) func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)

View File

@ -1165,92 +1165,93 @@ func (n *Node) stmtfmt(s fmt.State, mode fmtMode) {
} }
var opprec = []int{ var opprec = []int{
OALIGNOF: 8, OALIGNOF: 8,
OAPPEND: 8, OAPPEND: 8,
OBYTES2STR: 8, OBYTES2STR: 8,
OARRAYLIT: 8, OARRAYLIT: 8,
OSLICELIT: 8, OSLICELIT: 8,
ORUNES2STR: 8, ORUNES2STR: 8,
OCALLFUNC: 8, OCALLFUNC: 8,
OCALLINTER: 8, OCALLINTER: 8,
OCALLMETH: 8, OCALLMETH: 8,
OCALL: 8, OCALL: 8,
OCAP: 8, OCAP: 8,
OCLOSE: 8, OCLOSE: 8,
OCONVIFACE: 8, OCONVIFACE: 8,
OCONVNOP: 8, OCONVNOP: 8,
OCONV: 8, OCONV: 8,
OCOPY: 8, OCOPY: 8,
ODELETE: 8, ODELETE: 8,
OGETG: 8, OGETG: 8,
OLEN: 8, OLEN: 8,
OLITERAL: 8, OLITERAL: 8,
OMAKESLICE: 8, OMAKESLICE: 8,
OMAKE: 8, OMAKESLICECOPY: 8,
OMAPLIT: 8, OMAKE: 8,
ONAME: 8, OMAPLIT: 8,
ONEW: 8, ONAME: 8,
ONONAME: 8, ONEW: 8,
OOFFSETOF: 8, ONONAME: 8,
OPACK: 8, OOFFSETOF: 8,
OPANIC: 8, OPACK: 8,
OPAREN: 8, OPANIC: 8,
OPRINTN: 8, OPAREN: 8,
OPRINT: 8, OPRINTN: 8,
ORUNESTR: 8, OPRINT: 8,
OSIZEOF: 8, ORUNESTR: 8,
OSTR2BYTES: 8, OSIZEOF: 8,
OSTR2RUNES: 8, OSTR2BYTES: 8,
OSTRUCTLIT: 8, OSTR2RUNES: 8,
OTARRAY: 8, OSTRUCTLIT: 8,
OTCHAN: 8, OTARRAY: 8,
OTFUNC: 8, OTCHAN: 8,
OTINTER: 8, OTFUNC: 8,
OTMAP: 8, OTINTER: 8,
OTSTRUCT: 8, OTMAP: 8,
OINDEXMAP: 8, OTSTRUCT: 8,
OINDEX: 8, OINDEXMAP: 8,
OSLICE: 8, OINDEX: 8,
OSLICESTR: 8, OSLICE: 8,
OSLICEARR: 8, OSLICESTR: 8,
OSLICE3: 8, OSLICEARR: 8,
OSLICE3ARR: 8, OSLICE3: 8,
OSLICEHEADER: 8, OSLICE3ARR: 8,
ODOTINTER: 8, OSLICEHEADER: 8,
ODOTMETH: 8, ODOTINTER: 8,
ODOTPTR: 8, ODOTMETH: 8,
ODOTTYPE2: 8, ODOTPTR: 8,
ODOTTYPE: 8, ODOTTYPE2: 8,
ODOT: 8, ODOTTYPE: 8,
OXDOT: 8, ODOT: 8,
OCALLPART: 8, OXDOT: 8,
OPLUS: 7, OCALLPART: 8,
ONOT: 7, OPLUS: 7,
OBITNOT: 7, ONOT: 7,
ONEG: 7, OBITNOT: 7,
OADDR: 7, ONEG: 7,
ODEREF: 7, OADDR: 7,
ORECV: 7, ODEREF: 7,
OMUL: 6, ORECV: 7,
ODIV: 6, OMUL: 6,
OMOD: 6, ODIV: 6,
OLSH: 6, OMOD: 6,
ORSH: 6, OLSH: 6,
OAND: 6, ORSH: 6,
OANDNOT: 6, OAND: 6,
OADD: 5, OANDNOT: 6,
OSUB: 5, OADD: 5,
OOR: 5, OSUB: 5,
OXOR: 5, OOR: 5,
OEQ: 4, OXOR: 5,
OLT: 4, OEQ: 4,
OLE: 4, OLT: 4,
OGE: 4, OLE: 4,
OGT: 4, OGE: 4,
ONE: 4, OGT: 4,
OSEND: 3, ONE: 4,
OANDAND: 2, OSEND: 3,
OOROR: 1, OANDAND: 2,
OOROR: 1,
// Statements handled by stmtfmt // Statements handled by stmtfmt
OAS: -1, OAS: -1,
@ -1572,6 +1573,9 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
} }
mode.Fprintf(s, "make(%v)", n.Type) mode.Fprintf(s, "make(%v)", n.Type)
case OMAKESLICECOPY:
mode.Fprintf(s, "makeslicecopy(%v, %v, %v)", n.Type, n.Left, n.Right)
case OPLUS, ONEG, OADDR, OBITNOT, ODEREF, ONOT, ORECV: case OPLUS, ONEG, OADDR, OBITNOT, ODEREF, ONOT, ORECV:
// Unary // Unary
mode.Fprintf(s, "%#v", n.Op) mode.Fprintf(s, "%#v", n.Op)

View File

@ -82,89 +82,90 @@ func _() {
_ = x[OMAKECHAN-71] _ = x[OMAKECHAN-71]
_ = x[OMAKEMAP-72] _ = x[OMAKEMAP-72]
_ = x[OMAKESLICE-73] _ = x[OMAKESLICE-73]
_ = x[OMUL-74] _ = x[OMAKESLICECOPY-74]
_ = x[ODIV-75] _ = x[OMUL-75]
_ = x[OMOD-76] _ = x[ODIV-76]
_ = x[OLSH-77] _ = x[OMOD-77]
_ = x[ORSH-78] _ = x[OLSH-78]
_ = x[OAND-79] _ = x[ORSH-79]
_ = x[OANDNOT-80] _ = x[OAND-80]
_ = x[ONEW-81] _ = x[OANDNOT-81]
_ = x[ONEWOBJ-82] _ = x[ONEW-82]
_ = x[ONOT-83] _ = x[ONEWOBJ-83]
_ = x[OBITNOT-84] _ = x[ONOT-84]
_ = x[OPLUS-85] _ = x[OBITNOT-85]
_ = x[ONEG-86] _ = x[OPLUS-86]
_ = x[OOROR-87] _ = x[ONEG-87]
_ = x[OPANIC-88] _ = x[OOROR-88]
_ = x[OPRINT-89] _ = x[OPANIC-89]
_ = x[OPRINTN-90] _ = x[OPRINT-90]
_ = x[OPAREN-91] _ = x[OPRINTN-91]
_ = x[OSEND-92] _ = x[OPAREN-92]
_ = x[OSLICE-93] _ = x[OSEND-93]
_ = x[OSLICEARR-94] _ = x[OSLICE-94]
_ = x[OSLICESTR-95] _ = x[OSLICEARR-95]
_ = x[OSLICE3-96] _ = x[OSLICESTR-96]
_ = x[OSLICE3ARR-97] _ = x[OSLICE3-97]
_ = x[OSLICEHEADER-98] _ = x[OSLICE3ARR-98]
_ = x[ORECOVER-99] _ = x[OSLICEHEADER-99]
_ = x[ORECV-100] _ = x[ORECOVER-100]
_ = x[ORUNESTR-101] _ = x[ORECV-101]
_ = x[OSELRECV-102] _ = x[ORUNESTR-102]
_ = x[OSELRECV2-103] _ = x[OSELRECV-103]
_ = x[OIOTA-104] _ = x[OSELRECV2-104]
_ = x[OREAL-105] _ = x[OIOTA-105]
_ = x[OIMAG-106] _ = x[OREAL-106]
_ = x[OCOMPLEX-107] _ = x[OIMAG-107]
_ = x[OALIGNOF-108] _ = x[OCOMPLEX-108]
_ = x[OOFFSETOF-109] _ = x[OALIGNOF-109]
_ = x[OSIZEOF-110] _ = x[OOFFSETOF-110]
_ = x[OBLOCK-111] _ = x[OSIZEOF-111]
_ = x[OBREAK-112] _ = x[OBLOCK-112]
_ = x[OCASE-113] _ = x[OBREAK-113]
_ = x[OCONTINUE-114] _ = x[OCASE-114]
_ = x[ODEFER-115] _ = x[OCONTINUE-115]
_ = x[OEMPTY-116] _ = x[ODEFER-116]
_ = x[OFALL-117] _ = x[OEMPTY-117]
_ = x[OFOR-118] _ = x[OFALL-118]
_ = x[OFORUNTIL-119] _ = x[OFOR-119]
_ = x[OGOTO-120] _ = x[OFORUNTIL-120]
_ = x[OIF-121] _ = x[OGOTO-121]
_ = x[OLABEL-122] _ = x[OIF-122]
_ = x[OGO-123] _ = x[OLABEL-123]
_ = x[ORANGE-124] _ = x[OGO-124]
_ = x[ORETURN-125] _ = x[ORANGE-125]
_ = x[OSELECT-126] _ = x[ORETURN-126]
_ = x[OSWITCH-127] _ = x[OSELECT-127]
_ = x[OTYPESW-128] _ = x[OSWITCH-128]
_ = x[OTCHAN-129] _ = x[OTYPESW-129]
_ = x[OTMAP-130] _ = x[OTCHAN-130]
_ = x[OTSTRUCT-131] _ = x[OTMAP-131]
_ = x[OTINTER-132] _ = x[OTSTRUCT-132]
_ = x[OTFUNC-133] _ = x[OTINTER-133]
_ = x[OTARRAY-134] _ = x[OTFUNC-134]
_ = x[ODDD-135] _ = x[OTARRAY-135]
_ = x[OINLCALL-136] _ = x[ODDD-136]
_ = x[OEFACE-137] _ = x[OINLCALL-137]
_ = x[OITAB-138] _ = x[OEFACE-138]
_ = x[OIDATA-139] _ = x[OITAB-139]
_ = x[OSPTR-140] _ = x[OIDATA-140]
_ = x[OCLOSUREVAR-141] _ = x[OSPTR-141]
_ = x[OCFUNC-142] _ = x[OCLOSUREVAR-142]
_ = x[OCHECKNIL-143] _ = x[OCFUNC-143]
_ = x[OVARDEF-144] _ = x[OCHECKNIL-144]
_ = x[OVARKILL-145] _ = x[OVARDEF-145]
_ = x[OVARLIVE-146] _ = x[OVARKILL-146]
_ = x[ORESULT-147] _ = x[OVARLIVE-147]
_ = x[OINLMARK-148] _ = x[ORESULT-148]
_ = x[ORETJMP-149] _ = x[OINLMARK-149]
_ = x[OGETG-150] _ = x[ORETJMP-150]
_ = x[OEND-151] _ = x[OGETG-151]
_ = x[OEND-152]
} }
const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMULDIVMODLSHRSHANDANDNOTNEWNEWOBJNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKRETJMPGETGEND" const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNEWOBJNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKRETJMPGETGEND"
var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 70, 82, 91, 100, 112, 121, 123, 126, 136, 143, 150, 157, 161, 165, 173, 181, 190, 198, 201, 206, 213, 220, 226, 235, 243, 251, 257, 261, 270, 277, 281, 284, 291, 299, 307, 314, 320, 323, 329, 336, 344, 348, 355, 363, 365, 367, 369, 371, 373, 375, 380, 385, 393, 396, 405, 408, 412, 420, 427, 436, 439, 442, 445, 448, 451, 454, 460, 463, 469, 472, 478, 482, 485, 489, 494, 499, 505, 510, 514, 519, 527, 535, 541, 550, 561, 568, 572, 579, 586, 594, 598, 602, 606, 613, 620, 628, 634, 639, 644, 648, 656, 661, 666, 670, 673, 681, 685, 687, 692, 694, 699, 705, 711, 717, 723, 728, 732, 739, 745, 750, 756, 759, 766, 771, 775, 780, 784, 794, 799, 807, 813, 820, 827, 833, 840, 846, 850, 853} var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 70, 82, 91, 100, 112, 121, 123, 126, 136, 143, 150, 157, 161, 165, 173, 181, 190, 198, 201, 206, 213, 220, 226, 235, 243, 251, 257, 261, 270, 277, 281, 284, 291, 299, 307, 314, 320, 323, 329, 336, 344, 348, 355, 363, 365, 367, 369, 371, 373, 375, 380, 385, 393, 396, 405, 408, 412, 420, 427, 436, 449, 452, 455, 458, 461, 464, 467, 473, 476, 482, 485, 491, 495, 498, 502, 507, 512, 518, 523, 527, 532, 540, 548, 554, 563, 574, 581, 585, 592, 599, 607, 611, 615, 619, 626, 633, 641, 647, 652, 657, 661, 669, 674, 679, 683, 686, 694, 698, 700, 705, 707, 712, 718, 724, 730, 736, 741, 745, 752, 758, 763, 769, 772, 779, 784, 788, 793, 797, 807, 812, 820, 826, 833, 840, 846, 853, 859, 863, 866}
func (i Op) String() string { func (i Op) String() string {
if i >= Op(len(_Op_index)-1) { if i >= Op(len(_Op_index)-1) {

View File

@ -319,11 +319,82 @@ func (o *Order) cleanTemp(top ordermarker) {
// stmtList orders each of the statements in the list. // stmtList orders each of the statements in the list.
func (o *Order) stmtList(l Nodes) { func (o *Order) stmtList(l Nodes) {
for _, n := range l.Slice() { s := l.Slice()
o.stmt(n) for i := range s {
orderMakeSliceCopy(s[i:])
o.stmt(s[i])
} }
} }
// orderMakeSliceCopy matches the pattern:
// m = OMAKESLICE([]T, x); OCOPY(m, s)
// and rewrites it to:
// m = OMAKESLICECOPY([]T, x, s); nil
func orderMakeSliceCopy(s []*Node) {
const go115makeslicecopy = true
if !go115makeslicecopy {
return
}
if Debug['N'] != 0 || instrumenting {
return
}
if len(s) < 2 {
return
}
asn := s[0]
copyn := s[1]
if asn == nil || asn.Op != OAS {
return
}
if asn.Left.Op != ONAME {
return
}
if asn.Left.isBlank() {
return
}
maken := asn.Right
if maken == nil || maken.Op != OMAKESLICE {
return
}
if maken.Esc == EscNone {
return
}
if maken.Left == nil || maken.Right != nil {
return
}
if copyn.Op != OCOPY {
return
}
if copyn.Left.Op != ONAME {
return
}
if asn.Left.Sym != copyn.Left.Sym {
return
}
if copyn.Right.Op != ONAME {
return
}
if copyn.Left.Sym == copyn.Right.Sym {
return
}
maken.Op = OMAKESLICECOPY
maken.Right = copyn.Right
// Set bounded when m = OMAKESLICE([]T, len(s)); OCOPY(m, s)
maken.SetBounded(maken.Left.Op == OLEN && samesafeexpr(maken.Left.Left, copyn.Right))
maken = typecheck(maken, ctxExpr)
s[1] = nil // remove separate copy call
return
}
// edge inserts coverage instrumentation for libfuzzer. // edge inserts coverage instrumentation for libfuzzer.
func (o *Order) edge() { func (o *Order) edge() {
if Debug_libfuzzer == 0 { if Debug_libfuzzer == 0 {
@ -1150,6 +1221,7 @@ func (o *Order) expr(n, lhs *Node) *Node {
OMAKECHAN, OMAKECHAN,
OMAKEMAP, OMAKEMAP,
OMAKESLICE, OMAKESLICE,
OMAKESLICECOPY,
ONEW, ONEW,
OREAL, OREAL,
ORECOVER, ORECOVER,

View File

@ -208,12 +208,16 @@ func (n *Node) MarkNonNil() {
// SetBounded indicates whether operation n does not need safety checks. // SetBounded indicates whether operation n does not need safety checks.
// When n is an index or slice operation, n does not need bounds checks. // When n is an index or slice operation, n does not need bounds checks.
// When n is a dereferencing operation, n does not need nil checks. // When n is a dereferencing operation, n does not need nil checks.
// When n is a makeslice+copy operation, n does not need length and cap checks.
func (n *Node) SetBounded(b bool) { func (n *Node) SetBounded(b bool) {
switch n.Op { switch n.Op {
case OINDEX, OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR: case OINDEX, OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
// No bounds checks needed. // No bounds checks needed.
case ODOTPTR, ODEREF: case ODOTPTR, ODEREF:
// No nil check needed. // No nil check needed.
case OMAKESLICECOPY:
// No length and cap checks needed
// since new slice and copied over slice data have same length.
default: default:
Fatalf("SetBounded(%v)", n) Fatalf("SetBounded(%v)", n)
} }
@ -714,30 +718,38 @@ const (
ODCLCONST // const pi = 3.14 ODCLCONST // const pi = 3.14
ODCLTYPE // type Int int or type Int = int ODCLTYPE // type Int int or type Int = int
ODELETE // delete(Left, Right) ODELETE // delete(Left, Right)
ODOT // Left.Sym (Left is of struct type) ODOT // Left.Sym (Left is of struct type)
ODOTPTR // Left.Sym (Left is of pointer to struct type) ODOTPTR // Left.Sym (Left is of pointer to struct type)
ODOTMETH // Left.Sym (Left is non-interface, Right is method name) ODOTMETH // Left.Sym (Left is non-interface, Right is method name)
ODOTINTER // Left.Sym (Left is interface, Right is method name) ODOTINTER // Left.Sym (Left is interface, Right is method name)
OXDOT // Left.Sym (before rewrite to one of the preceding) OXDOT // Left.Sym (before rewrite to one of the preceding)
ODOTTYPE // Left.Right or Left.Type (.Right during parsing, .Type once resolved); after walk, .Right contains address of interface type descriptor and .Right.Right contains address of concrete type descriptor ODOTTYPE // Left.Right or Left.Type (.Right during parsing, .Type once resolved); after walk, .Right contains address of interface type descriptor and .Right.Right contains address of concrete type descriptor
ODOTTYPE2 // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE); after walk, .Right contains address of interface type descriptor ODOTTYPE2 // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE); after walk, .Right contains address of interface type descriptor
OEQ // Left == Right OEQ // Left == Right
ONE // Left != Right ONE // Left != Right
OLT // Left < Right OLT // Left < Right
OLE // Left <= Right OLE // Left <= Right
OGE // Left >= Right OGE // Left >= Right
OGT // Left > Right OGT // Left > Right
ODEREF // *Left ODEREF // *Left
OINDEX // Left[Right] (index of array or slice) OINDEX // Left[Right] (index of array or slice)
OINDEXMAP // Left[Right] (index of map) OINDEXMAP // Left[Right] (index of map)
OKEY // Left:Right (key:value in struct/array/map literal) OKEY // Left:Right (key:value in struct/array/map literal)
OSTRUCTKEY // Sym:Left (key:value in struct literal, after type checking) OSTRUCTKEY // Sym:Left (key:value in struct literal, after type checking)
OLEN // len(Left) OLEN // len(Left)
OMAKE // make(List) (before type checking converts to one of the following) OMAKE // make(List) (before type checking converts to one of the following)
OMAKECHAN // make(Type, Left) (type is chan) OMAKECHAN // make(Type, Left) (type is chan)
OMAKEMAP // make(Type, Left) (type is map) OMAKEMAP // make(Type, Left) (type is map)
OMAKESLICE // make(Type, Left, Right) (type is slice) OMAKESLICE // make(Type, Left, Right) (type is slice)
OMAKESLICECOPY // makeslicecopy(Type, Left, Right) (type is slice; Left is length and Right is the copied from slice)
// OMAKESLICECOPY is created by the order pass and corresponds to:
// s = make(Type, Left); copy(s, Right)
//
// Bounded can be set on the node when Left == len(Right) is known at compile time.
//
// This node is created so the walk pass can optimize this pattern which would
// otherwise be hard to detect after the order pass.
OMUL // Left * Right OMUL // Left * Right
ODIV // Left / Right ODIV // Left / Right
OMOD // Left % Right OMOD // Left % Right

View File

@ -1149,6 +1149,49 @@ func typecheck1(n *Node, top int) (res *Node) {
n.List.SetFirst(l) n.List.SetFirst(l)
n.List.SetSecond(c) n.List.SetSecond(c)
case OMAKESLICECOPY:
// Errors here are Fatalf instead of yyerror because only the compiler
// can construct an OMAKESLICECOPY node.
// Components used in OMAKESCLICECOPY that are supplied by parsed source code
// have already been typechecked in OMAKE and OCOPY earlier.
ok |= ctxExpr
t := n.Type
if t == nil {
Fatalf("no type specified for OMAKESLICECOPY")
}
if !t.IsSlice() {
Fatalf("invalid type %v for OMAKESLICECOPY", n.Type)
}
if n.Left == nil {
Fatalf("missing len argument for OMAKESLICECOPY")
}
if n.Right == nil {
Fatalf("missing slice argument to copy for OMAKESLICECOPY")
}
n.Left = typecheck(n.Left, ctxExpr)
n.Right = typecheck(n.Right, ctxExpr)
n.Left = defaultlit(n.Left, types.Types[TINT])
if !n.Left.Type.IsInteger() && n.Type.Etype != TIDEAL {
yyerror("non-integer len argument in OMAKESLICECOPY")
}
if Isconst(n.Left, CTINT) {
if n.Left.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
Fatalf("len for OMAKESLICECOPY too large")
}
if n.Left.Int64() < 0 {
Fatalf("len for OMAKESLICECOPY must be non-negative")
}
}
case OSLICE, OSLICE3: case OSLICE, OSLICE3:
ok |= ctxExpr ok |= ctxExpr
n.Left = typecheck(n.Left, ctxExpr) n.Left = typecheck(n.Left, ctxExpr)

View File

@ -1390,6 +1390,63 @@ opswitch:
n = m n = m
} }
case OMAKESLICECOPY:
if n.Esc == EscNone {
Fatalf("OMAKESLICECOPY with EscNone: %v", n)
}
t := n.Type
if t.Elem().NotInHeap() {
Fatalf("%v is go:notinheap; heap allocation disallowed", t.Elem())
}
length := conv(n.Left, types.Types[TINT])
copylen := nod(OLEN, n.Right, nil)
copyptr := nod(OSPTR, n.Right, nil)
if !types.Haspointers(t.Elem()) && n.Bounded() {
// When len(to)==len(from) and elements have no pointers:
// replace make+copy with runtime.mallocgc+runtime.memmove.
// We do not check for overflow of len(to)*elem.Width here
// since len(from) is an existing checked slice capacity
// with same elem.Width for the from slice.
size := nod(OMUL, conv(length, types.Types[TUINTPTR]), conv(nodintconst(t.Elem().Width), types.Types[TUINTPTR]))
// instantiate mallocgc(size uintptr, typ *byte, needszero bool) unsafe.Pointer
fn := syslook("mallocgc")
sh := nod(OSLICEHEADER, nil, nil)
sh.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, size, nodnil(), nodbool(false))
sh.Left.MarkNonNil()
sh.List.Set2(length, length)
sh.Type = t
s := temp(t)
r := typecheck(nod(OAS, s, sh), ctxStmt)
r = walkexpr(r, init)
init.Append(r)
// instantiate memmove(to *any, frm *any, size uintptr)
fn = syslook("memmove")
fn = substArgTypes(fn, t.Elem(), t.Elem())
ncopy := mkcall1(fn, nil, init, nod(OSPTR, s, nil), copyptr, size)
ncopy = typecheck(ncopy, ctxStmt)
ncopy = walkexpr(ncopy, init)
init.Append(ncopy)
n = s
} else { // Replace make+copy with runtime.makeslicecopy.
// instantiate makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer
fn := syslook("makeslicecopy")
s := nod(OSLICEHEADER, nil, nil)
s.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, typename(t.Elem()), length, copylen, conv(copyptr, types.Types[TUNSAFEPTR]))
s.Left.MarkNonNil()
s.List.Set2(length, length)
s.Type = t
n = typecheck(s, ctxExpr)
n = walkexpr(n, init)
}
case ORUNESTR: case ORUNESTR:
a := nodnil() a := nodnil()
if n.Esc == EscNone { if n.Esc == EscNone {
@ -3772,6 +3829,9 @@ func candiscard(n *Node) bool {
// Difficult to tell what sizes are okay. // Difficult to tell what sizes are okay.
case OMAKESLICE: case OMAKESLICE:
return false return false
case OMAKESLICECOPY:
return false
} }
if !candiscard(n.Left) || !candiscard(n.Right) || !candiscardlist(n.Ninit) || !candiscardlist(n.Nbody) || !candiscardlist(n.List) || !candiscardlist(n.Rlist) { if !candiscard(n.Left) || !candiscard(n.Right) || !candiscardlist(n.Ninit) || !candiscardlist(n.Nbody) || !candiscardlist(n.List) || !candiscardlist(n.Rlist) {

View File

@ -31,6 +31,55 @@ func panicmakeslicecap() {
panic(errorString("makeslice: cap out of range")) panic(errorString("makeslice: cap out of range"))
} }
// makeslicecopy allocates a slice of "tolen" elements of type "et",
// then copies "fromlen" elements of type "et" into that new allocation from "from".
func makeslicecopy(et *_type, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer {
var tomem, copymem uintptr
if uintptr(tolen) > uintptr(fromlen) {
var overflow bool
tomem, overflow = math.MulUintptr(et.size, uintptr(tolen))
if overflow || tomem > maxAlloc || tolen < 0 {
panicmakeslicelen()
}
copymem = et.size * uintptr(fromlen)
} else {
// fromlen is a known good length providing and equal or greater than tolen,
// thereby making tolen a good slice length too as from and to slices have the
// same element width.
tomem = et.size * uintptr(tolen)
copymem = tomem
}
var to unsafe.Pointer
if et.ptrdata == 0 {
to = mallocgc(tomem, nil, false)
if copymem < tomem {
memclrNoHeapPointers(add(to, copymem), tomem-copymem)
}
} else {
// Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory.
to = mallocgc(tomem, et, true)
if writeBarrier.enabled {
// Only shade the pointers in old.array since we know the destination slice to
// only contains nil pointers because it has been cleared during alloc.
bulkBarrierPreWriteSrcOnly(uintptr(to), uintptr(from), copymem)
}
}
if raceenabled {
callerpc := getcallerpc()
pc := funcPC(makeslicecopy)
racereadrangepc(from, copymem, callerpc, pc)
}
if msanenabled {
msanread(from, copymem)
}
memmove(to, from, copymem)
return to
}
func makeslice(et *_type, len, cap int) unsafe.Pointer { func makeslice(et *_type, len, cap int) unsafe.Pointer {
mem, overflow := math.MulUintptr(et.size, uintptr(cap)) mem, overflow := math.MulUintptr(et.size, uintptr(cap))
if overflow || mem > maxAlloc || len < 0 || len > cap { if overflow || mem > maxAlloc || len < 0 || len > cap {

View File

@ -10,6 +10,84 @@ import (
const N = 20 const N = 20
func BenchmarkMakeSliceCopy(b *testing.B) {
const length = 32
var bytes = make([]byte, 8*length)
var ints = make([]int, length)
var ptrs = make([]*byte, length)
b.Run("mallocmove", func(b *testing.B) {
b.Run("Byte", func(b *testing.B) {
var x []byte
for i := 0; i < b.N; i++ {
x = make([]byte, len(bytes))
copy(x, bytes)
}
})
b.Run("Int", func(b *testing.B) {
var x []int
for i := 0; i < b.N; i++ {
x = make([]int, len(ints))
copy(x, ints)
}
})
b.Run("Ptr", func(b *testing.B) {
var x []*byte
for i := 0; i < b.N; i++ {
x = make([]*byte, len(ptrs))
copy(x, ptrs)
}
})
})
b.Run("makecopy", func(b *testing.B) {
b.Run("Byte", func(b *testing.B) {
var x []byte
for i := 0; i < b.N; i++ {
x = make([]byte, 8*length)
copy(x, bytes)
}
})
b.Run("Int", func(b *testing.B) {
var x []int
for i := 0; i < b.N; i++ {
x = make([]int, length)
copy(x, ints)
}
})
b.Run("Ptr", func(b *testing.B) {
var x []*byte
for i := 0; i < b.N; i++ {
x = make([]*byte, length)
copy(x, ptrs)
}
})
})
b.Run("nilappend", func(b *testing.B) {
b.Run("Byte", func(b *testing.B) {
var x []byte
for i := 0; i < b.N; i++ {
x = append([]byte(nil), bytes...)
_ = x
}
})
b.Run("Int", func(b *testing.B) {
var x []int
for i := 0; i < b.N; i++ {
x = append([]int(nil), ints...)
_ = x
}
})
b.Run("Ptr", func(b *testing.B) {
var x []*byte
for i := 0; i < b.N; i++ {
x = append([]*byte(nil), ptrs...)
_ = x
}
})
})
}
type ( type (
struct24 struct{ a, b, c int64 } struct24 struct{ a, b, c int64 }
struct32 struct{ a, b, c, d int64 } struct32 struct{ a, b, c, d int64 }

View File

@ -104,6 +104,189 @@ func SliceExtensionInt64(s []int, l64 int64) []int {
return append(s, make([]int, l64)...) return append(s, make([]int, l64)...)
} }
// ------------------ //
// Make+Copy //
// ------------------ //
// Issue #26252 - avoid memclr for make+copy
func SliceMakeCopyLen(s []int) []int {
// amd64:`.*runtime\.mallocgc`
// amd64:`.*runtime\.memmove`
// amd64:-`.*runtime\.makeslice`
a := make([]int, len(s))
copy(a, s)
return a
}
func SliceMakeCopyLenPtr(s []*int) []*int {
// amd64:`.*runtime\.makeslicecopy`
// amd64:-`.*runtime\.makeslice\(`
// amd64:-`.*runtime\.typedslicecopy
a := make([]*int, len(s))
copy(a, s)
return a
}
func SliceMakeCopyConst(s []int) []int {
// amd64:`.*runtime\.makeslicecopy`
// amd64:-`.*runtime\.makeslice\(`
// amd64:-`.*runtime\.memmove`
a := make([]int, 4)
copy(a, s)
return a
}
func SliceMakeCopyConstPtr(s []*int) []*int {
// amd64:`.*runtime\.makeslicecopy`
// amd64:-`.*runtime\.makeslice\(`
// amd64:-`.*runtime\.typedslicecopy
a := make([]*int, 4)
copy(a, s)
return a
}
func SliceMakeCopyNoOptNoDeref(s []*int) []*int {
a := new([]*int)
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.makeslice\(`
*a = make([]*int, 4)
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.typedslicecopy`
copy(*a, s)
return *a
}
func SliceMakeCopyNoOptNoVar(s []*int) []*int {
a := make([][]*int, 1)
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.makeslice\(`
a[0] = make([]*int, 4)
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.typedslicecopy`
copy(a[0], s)
return a[0]
}
func SliceMakeCopyNoOptBlank(s []*int) []*int {
var a []*int
// amd64:-`.*runtime\.makeslicecopy`
_ = make([]*int, 4)
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.typedslicecopy`
copy(a, s)
return a
}
func SliceMakeCopyNoOptNoMake(s []*int) []*int {
// amd64:-`.*runtime\.makeslicecopy`
// amd64:-`.*runtime\.objectnew`
a := *new([]*int)
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.typedslicecopy`
copy(a, s)
return a
}
func SliceMakeCopyNoOptNoHeapAlloc(s []*int) int {
// amd64:-`.*runtime\.makeslicecopy`
a := make([]*int, 4)
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.typedslicecopy`
copy(a, s)
return cap(a)
}
func SliceMakeCopyNoOptNoCap(s []*int) []*int {
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.makeslice\(`
a := make([]*int, 0, 4)
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.typedslicecopy`
copy(a, s)
return a
}
func SliceMakeCopyNoOptNoCopy(s []*int) []*int {
copy := func(x, y []*int) {}
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.makeslice\(`
a := make([]*int, 4)
// amd64:-`.*runtime\.makeslicecopy`
copy(a, s)
return a
}
func SliceMakeCopyNoOptWrongOrder(s []*int) []*int {
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.makeslice\(`
a := make([]*int, 4)
// amd64:`.*runtime\.typedslicecopy`
// amd64:-`.*runtime\.makeslicecopy`
copy(s, a)
return a
}
func SliceMakeCopyNoOptWrongAssign(s []*int) []*int {
var a []*int
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.makeslice\(`
s = make([]*int, 4)
// amd64:`.*runtime\.typedslicecopy`
// amd64:-`.*runtime\.makeslicecopy`
copy(a, s)
return s
}
func SliceMakeCopyNoOptCopyLength(s []*int) (int, []*int) {
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.makeslice\(`
a := make([]*int, 4)
// amd64:`.*runtime\.typedslicecopy`
// amd64:-`.*runtime\.makeslicecopy`
n := copy(a, s)
return n, a
}
func SliceMakeCopyNoOptSelfCopy(s []*int) []*int {
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.makeslice\(`
a := make([]*int, 4)
// amd64:`.*runtime\.typedslicecopy`
// amd64:-`.*runtime\.makeslicecopy`
copy(a, a)
return a
}
func SliceMakeCopyNoOptTargetReference(s []*int) []*int {
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.makeslice\(`
a := make([]*int, 4)
// amd64:`.*runtime\.typedslicecopy`
// amd64:-`.*runtime\.makeslicecopy`
copy(a, s[:len(a)])
return a
}
func SliceMakeCopyNoOptCap(s []int) []int {
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.makeslice\(`
a := make([]int, len(s), 9)
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.memmove`
copy(a, s)
return a
}
func SliceMakeCopyNoMemmoveDifferentLen(s []int) []int {
// amd64:`.*runtime\.makeslicecopy`
// amd64:-`.*runtime\.memmove`
a := make([]int, len(s)-1)
// amd64:-`.*runtime\.memmove`
copy(a, s)
return a
}
// ---------------------- // // ---------------------- //
// Nil check of &s[0] // // Nil check of &s[0] //
// ---------------------- // // ---------------------- //

149
test/makeslice.go Normal file
View File

@ -0,0 +1,149 @@
// run
// Copyright 2013 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 main
import (
"strings"
"unsafe"
)
func main() {
n := -1
testInts(uint64(n))
testBytes(uint64(n))
var t *byte
if unsafe.Sizeof(t) == 8 {
// Test mem > maxAlloc
testInts(1 << 59)
// Test elem.size*cap overflow
testInts(1<<63 - 1)
testInts(1<<64 - 1)
testBytes(1<<64 - 1)
} else {
testInts(1<<31 - 1)
// Test elem.size*cap overflow
testInts(1<<32 - 1)
testBytes(1<<32 - 1)
}
}
func shouldPanic(str string, f func()) {
defer func() {
err := recover()
if err == nil {
panic("did not panic")
}
s := err.(error).Error()
if !strings.Contains(s, str) {
panic("got panic " + s + ", want " + str)
}
}()
f()
}
func testInts(n uint64) {
testMakeInts(n)
testMakeCopyInts(n)
testMakeInAppendInts(n)
}
func testBytes(n uint64) {
testMakeBytes(n)
testMakeCopyBytes(n)
testMakeInAppendBytes(n)
}
// Test make panics for given length or capacity n.
func testMakeInts(n uint64) {
type T []int
shouldPanic("len out of range", func() { _ = make(T, int(n)) })
shouldPanic("cap out of range", func() { _ = make(T, 0, int(n)) })
shouldPanic("len out of range", func() { _ = make(T, uint(n)) })
shouldPanic("cap out of range", func() { _ = make(T, 0, uint(n)) })
shouldPanic("len out of range", func() { _ = make(T, int64(n)) })
shouldPanic("cap out of range", func() { _ = make(T, 0, int64(n)) })
shouldPanic("len out of range", func() { _ = make(T, uint64(n)) })
shouldPanic("cap out of range", func() { _ = make(T, 0, uint64(n)) })
}
func testMakeBytes(n uint64) {
type T []byte
shouldPanic("len out of range", func() { _ = make(T, int(n)) })
shouldPanic("cap out of range", func() { _ = make(T, 0, int(n)) })
shouldPanic("len out of range", func() { _ = make(T, uint(n)) })
shouldPanic("cap out of range", func() { _ = make(T, 0, uint(n)) })
shouldPanic("len out of range", func() { _ = make(T, int64(n)) })
shouldPanic("cap out of range", func() { _ = make(T, 0, int64(n)) })
shouldPanic("len out of range", func() { _ = make(T, uint64(n)) })
shouldPanic("cap out of range", func() { _ = make(T, 0, uint64(n)) })
}
// Test make+copy panics since the gc compiler optimizes these
// to runtime.makeslicecopy calls.
func testMakeCopyInts(n uint64) {
type T []int
var c = make(T, 8)
shouldPanic("len out of range", func() { x := make(T, int(n)); copy(x, c) })
shouldPanic("cap out of range", func() { x := make(T, 0, int(n)); copy(x, c) })
shouldPanic("len out of range", func() { x := make(T, uint(n)); copy(x, c) })
shouldPanic("cap out of range", func() { x := make(T, 0, uint(n)); copy(x, c) })
shouldPanic("len out of range", func() { x := make(T, int64(n)); copy(x, c) })
shouldPanic("cap out of range", func() { x := make(T, 0, int64(n)); copy(x, c) })
shouldPanic("len out of range", func() { x := make(T, uint64(n)); copy(x, c) })
shouldPanic("cap out of range", func() { x := make(T, 0, uint64(n)); copy(x, c) })
}
func testMakeCopyBytes(n uint64) {
type T []byte
var c = make(T, 8)
shouldPanic("len out of range", func() { x := make(T, int(n)); copy(x, c) })
shouldPanic("cap out of range", func() { x := make(T, 0, int(n)); copy(x, c) })
shouldPanic("len out of range", func() { x := make(T, uint(n)); copy(x, c) })
shouldPanic("cap out of range", func() { x := make(T, 0, uint(n)); copy(x, c) })
shouldPanic("len out of range", func() { x := make(T, int64(n)); copy(x, c) })
shouldPanic("cap out of range", func() { x := make(T, 0, int64(n)); copy(x, c) })
shouldPanic("len out of range", func() { x := make(T, uint64(n)); copy(x, c) })
shouldPanic("cap out of range", func() { x := make(T, 0, uint64(n)); copy(x, c) })
}
// Test make in append panics for int slices since the gc compiler optimizes makes in appends.
func testMakeInAppendInts(n uint64) {
type T []int
for _, length := range []int{0, 1} {
t := make(T, length)
shouldPanic("len out of range", func() { _ = append(t, make(T, int(n))...) })
shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int(n))...) })
shouldPanic("len out of range", func() { _ = append(t, make(T, int64(n))...) })
shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int64(n))...) })
shouldPanic("len out of range", func() { _ = append(t, make(T, uint64(n))...) })
shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, uint64(n))...) })
shouldPanic("len out of range", func() { _ = append(t, make(T, int(n))...) })
shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int(n))...) })
shouldPanic("len out of range", func() { _ = append(t, make(T, uint(n))...) })
shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, uint(n))...) })
}
}
func testMakeInAppendBytes(n uint64) {
type T []byte
for _, length := range []int{0, 1} {
t := make(T, length)
shouldPanic("len out of range", func() { _ = append(t, make(T, int(n))...) })
shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int(n))...) })
shouldPanic("len out of range", func() { _ = append(t, make(T, uint(n))...) })
shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, uint(n))...) })
shouldPanic("len out of range", func() { _ = append(t, make(T, int64(n))...) })
shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int64(n))...) })
shouldPanic("len out of range", func() { _ = append(t, make(T, uint64(n))...) })
shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, uint64(n))...) })
}
}