1
0
mirror of https://github.com/golang/go synced 2024-11-26 06:27:58 -07:00

cmd/compile: make interface conversion function selection ABI insensitive

Before register ABI, we always pass argument in memory, and the
compiler chooses interface conversion functions solely based on
the memory layout. As long as the two types have identical memory
layout, it is fine to mix and match, e.g. convT64 takes a uint64
argument, but it can be used for things like float64 or
struct { x [4]struct{}; y int64 }.

With register ABI, those types may be passed differently, e.g.
uint64 is passed in an integer register, float64 is passed in a
floating point register, the struct above is passed in memory.
I made a few attempts in the previous CLs to try to choose the
right function based on the argument type, but none of them is
really correct.

Instead, this CL changes it to always pass the argument in the
same type the runtime expects, and do conversion before the call
in the compiler. The conversion can be no-op (e.g. a named type
to its underlying type), direct (e.g. int64 to uint64), or
through memory (e.g. *(*uint64)(unsafe.Pointer(&arg))). This way,
the front end does not need to know the ABI. (It only needs to
know how to convert types, and it already does.)

TODO: do something similar for map functions.

Change-Id: I33fc780a47c3f332b765e09b5e527f52ea1d6b5c
Reviewed-on: https://go-review.googlesource.com/c/go/+/309029
Trust: Cherry Zhang <cherryyz@google.com>
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Cherry Zhang 2021-04-09 14:40:28 -04:00
parent 841bc14216
commit 49e933fc57
5 changed files with 247 additions and 263 deletions

View File

@ -71,135 +71,133 @@ var runtimeDecls = [...]struct {
{"decoderune", funcTag, 55}, {"decoderune", funcTag, 55},
{"countrunes", funcTag, 56}, {"countrunes", funcTag, 56},
{"convI2I", funcTag, 57}, {"convI2I", funcTag, 57},
{"convT16", funcTag, 58}, {"convT16", funcTag, 59},
{"convT32", funcTag, 58}, {"convT32", funcTag, 61},
{"convT32F", funcTag, 58}, {"convT64", funcTag, 62},
{"convT64", funcTag, 58}, {"convTstring", funcTag, 63},
{"convT64F", funcTag, 58}, {"convTslice", funcTag, 66},
{"convTstring", funcTag, 58}, {"convT2E", funcTag, 67},
{"convTslice", funcTag, 58}, {"convT2Enoptr", funcTag, 67},
{"convT2E", funcTag, 59}, {"convT2I", funcTag, 67},
{"convT2Enoptr", funcTag, 59}, {"convT2Inoptr", funcTag, 67},
{"convT2I", funcTag, 59}, {"assertE2I", funcTag, 68},
{"convT2Inoptr", funcTag, 59},
{"assertE2I", funcTag, 60},
{"assertE2I2", funcTag, 57}, {"assertE2I2", funcTag, 57},
{"assertI2I", funcTag, 60}, {"assertI2I", funcTag, 68},
{"assertI2I2", funcTag, 57}, {"assertI2I2", funcTag, 57},
{"panicdottypeE", funcTag, 61}, {"panicdottypeE", funcTag, 69},
{"panicdottypeI", funcTag, 61}, {"panicdottypeI", funcTag, 69},
{"panicnildottype", funcTag, 62}, {"panicnildottype", funcTag, 70},
{"ifaceeq", funcTag, 64}, {"ifaceeq", funcTag, 72},
{"efaceeq", funcTag, 64}, {"efaceeq", funcTag, 72},
{"fastrand", funcTag, 66}, {"fastrand", funcTag, 73},
{"makemap64", funcTag, 68}, {"makemap64", funcTag, 75},
{"makemap", funcTag, 69}, {"makemap", funcTag, 76},
{"makemap_small", funcTag, 70}, {"makemap_small", funcTag, 77},
{"mapaccess1", funcTag, 71}, {"mapaccess1", funcTag, 78},
{"mapaccess1_fast32", funcTag, 72}, {"mapaccess1_fast32", funcTag, 79},
{"mapaccess1_fast64", funcTag, 72}, {"mapaccess1_fast64", funcTag, 79},
{"mapaccess1_faststr", funcTag, 72}, {"mapaccess1_faststr", funcTag, 79},
{"mapaccess1_fat", funcTag, 73}, {"mapaccess1_fat", funcTag, 80},
{"mapaccess2", funcTag, 74}, {"mapaccess2", funcTag, 81},
{"mapaccess2_fast32", funcTag, 75}, {"mapaccess2_fast32", funcTag, 82},
{"mapaccess2_fast64", funcTag, 75}, {"mapaccess2_fast64", funcTag, 82},
{"mapaccess2_faststr", funcTag, 75}, {"mapaccess2_faststr", funcTag, 82},
{"mapaccess2_fat", funcTag, 76}, {"mapaccess2_fat", funcTag, 83},
{"mapassign", funcTag, 71}, {"mapassign", funcTag, 78},
{"mapassign_fast32", funcTag, 72}, {"mapassign_fast32", funcTag, 79},
{"mapassign_fast32ptr", funcTag, 72}, {"mapassign_fast32ptr", funcTag, 79},
{"mapassign_fast64", funcTag, 72}, {"mapassign_fast64", funcTag, 79},
{"mapassign_fast64ptr", funcTag, 72}, {"mapassign_fast64ptr", funcTag, 79},
{"mapassign_faststr", funcTag, 72}, {"mapassign_faststr", funcTag, 79},
{"mapiterinit", funcTag, 77}, {"mapiterinit", funcTag, 84},
{"mapdelete", funcTag, 77}, {"mapdelete", funcTag, 84},
{"mapdelete_fast32", funcTag, 78}, {"mapdelete_fast32", funcTag, 85},
{"mapdelete_fast64", funcTag, 78}, {"mapdelete_fast64", funcTag, 85},
{"mapdelete_faststr", funcTag, 78}, {"mapdelete_faststr", funcTag, 85},
{"mapiternext", funcTag, 79}, {"mapiternext", funcTag, 86},
{"mapclear", funcTag, 80}, {"mapclear", funcTag, 87},
{"makechan64", funcTag, 82}, {"makechan64", funcTag, 89},
{"makechan", funcTag, 83}, {"makechan", funcTag, 90},
{"chanrecv1", funcTag, 85}, {"chanrecv1", funcTag, 92},
{"chanrecv2", funcTag, 86}, {"chanrecv2", funcTag, 93},
{"chansend1", funcTag, 88}, {"chansend1", funcTag, 95},
{"closechan", funcTag, 30}, {"closechan", funcTag, 30},
{"writeBarrier", varTag, 90}, {"writeBarrier", varTag, 97},
{"typedmemmove", funcTag, 91}, {"typedmemmove", funcTag, 98},
{"typedmemclr", funcTag, 92}, {"typedmemclr", funcTag, 99},
{"typedslicecopy", funcTag, 93}, {"typedslicecopy", funcTag, 100},
{"selectnbsend", funcTag, 94}, {"selectnbsend", funcTag, 101},
{"selectnbrecv", funcTag, 95}, {"selectnbrecv", funcTag, 102},
{"selectsetpc", funcTag, 96}, {"selectsetpc", funcTag, 103},
{"selectgo", funcTag, 97}, {"selectgo", funcTag, 104},
{"block", funcTag, 9}, {"block", funcTag, 9},
{"makeslice", funcTag, 98}, {"makeslice", funcTag, 105},
{"makeslice64", funcTag, 99}, {"makeslice64", funcTag, 106},
{"makeslicecopy", funcTag, 100}, {"makeslicecopy", funcTag, 107},
{"growslice", funcTag, 102}, {"growslice", funcTag, 109},
{"memmove", funcTag, 103}, {"memmove", funcTag, 110},
{"memclrNoHeapPointers", funcTag, 104}, {"memclrNoHeapPointers", funcTag, 111},
{"memclrHasPointers", funcTag, 104}, {"memclrHasPointers", funcTag, 111},
{"memequal", funcTag, 105}, {"memequal", funcTag, 112},
{"memequal0", funcTag, 106}, {"memequal0", funcTag, 113},
{"memequal8", funcTag, 106}, {"memequal8", funcTag, 113},
{"memequal16", funcTag, 106}, {"memequal16", funcTag, 113},
{"memequal32", funcTag, 106}, {"memequal32", funcTag, 113},
{"memequal64", funcTag, 106}, {"memequal64", funcTag, 113},
{"memequal128", funcTag, 106}, {"memequal128", funcTag, 113},
{"f32equal", funcTag, 107}, {"f32equal", funcTag, 114},
{"f64equal", funcTag, 107}, {"f64equal", funcTag, 114},
{"c64equal", funcTag, 107}, {"c64equal", funcTag, 114},
{"c128equal", funcTag, 107}, {"c128equal", funcTag, 114},
{"strequal", funcTag, 107}, {"strequal", funcTag, 114},
{"interequal", funcTag, 107}, {"interequal", funcTag, 114},
{"nilinterequal", funcTag, 107}, {"nilinterequal", funcTag, 114},
{"memhash", funcTag, 108}, {"memhash", funcTag, 115},
{"memhash0", funcTag, 109}, {"memhash0", funcTag, 116},
{"memhash8", funcTag, 109}, {"memhash8", funcTag, 116},
{"memhash16", funcTag, 109}, {"memhash16", funcTag, 116},
{"memhash32", funcTag, 109}, {"memhash32", funcTag, 116},
{"memhash64", funcTag, 109}, {"memhash64", funcTag, 116},
{"memhash128", funcTag, 109}, {"memhash128", funcTag, 116},
{"f32hash", funcTag, 109}, {"f32hash", funcTag, 116},
{"f64hash", funcTag, 109}, {"f64hash", funcTag, 116},
{"c64hash", funcTag, 109}, {"c64hash", funcTag, 116},
{"c128hash", funcTag, 109}, {"c128hash", funcTag, 116},
{"strhash", funcTag, 109}, {"strhash", funcTag, 116},
{"interhash", funcTag, 109}, {"interhash", funcTag, 116},
{"nilinterhash", funcTag, 109}, {"nilinterhash", funcTag, 116},
{"int64div", funcTag, 110}, {"int64div", funcTag, 117},
{"uint64div", funcTag, 111}, {"uint64div", funcTag, 118},
{"int64mod", funcTag, 110}, {"int64mod", funcTag, 117},
{"uint64mod", funcTag, 111}, {"uint64mod", funcTag, 118},
{"float64toint64", funcTag, 112}, {"float64toint64", funcTag, 119},
{"float64touint64", funcTag, 113}, {"float64touint64", funcTag, 120},
{"float64touint32", funcTag, 114}, {"float64touint32", funcTag, 121},
{"int64tofloat64", funcTag, 115}, {"int64tofloat64", funcTag, 122},
{"uint64tofloat64", funcTag, 116}, {"uint64tofloat64", funcTag, 123},
{"uint32tofloat64", funcTag, 117}, {"uint32tofloat64", funcTag, 124},
{"complex128div", funcTag, 118}, {"complex128div", funcTag, 125},
{"getcallerpc", funcTag, 119}, {"getcallerpc", funcTag, 126},
{"getcallersp", funcTag, 119}, {"getcallersp", funcTag, 126},
{"racefuncenter", funcTag, 31}, {"racefuncenter", funcTag, 31},
{"racefuncexit", funcTag, 9}, {"racefuncexit", funcTag, 9},
{"raceread", funcTag, 31}, {"raceread", funcTag, 31},
{"racewrite", funcTag, 31}, {"racewrite", funcTag, 31},
{"racereadrange", funcTag, 120}, {"racereadrange", funcTag, 127},
{"racewriterange", funcTag, 120}, {"racewriterange", funcTag, 127},
{"msanread", funcTag, 120}, {"msanread", funcTag, 127},
{"msanwrite", funcTag, 120}, {"msanwrite", funcTag, 127},
{"msanmove", funcTag, 121}, {"msanmove", funcTag, 128},
{"checkptrAlignment", funcTag, 122}, {"checkptrAlignment", funcTag, 129},
{"checkptrArithmetic", funcTag, 124}, {"checkptrArithmetic", funcTag, 131},
{"libfuzzerTraceCmp1", funcTag, 126}, {"libfuzzerTraceCmp1", funcTag, 132},
{"libfuzzerTraceCmp2", funcTag, 128}, {"libfuzzerTraceCmp2", funcTag, 133},
{"libfuzzerTraceCmp4", funcTag, 129}, {"libfuzzerTraceCmp4", funcTag, 134},
{"libfuzzerTraceCmp8", funcTag, 130}, {"libfuzzerTraceCmp8", funcTag, 135},
{"libfuzzerTraceConstCmp1", funcTag, 126}, {"libfuzzerTraceConstCmp1", funcTag, 132},
{"libfuzzerTraceConstCmp2", funcTag, 128}, {"libfuzzerTraceConstCmp2", funcTag, 133},
{"libfuzzerTraceConstCmp4", funcTag, 129}, {"libfuzzerTraceConstCmp4", funcTag, 134},
{"libfuzzerTraceConstCmp8", funcTag, 130}, {"libfuzzerTraceConstCmp8", funcTag, 135},
{"x86HasPOPCNT", varTag, 6}, {"x86HasPOPCNT", varTag, 6},
{"x86HasSSE41", varTag, 6}, {"x86HasSSE41", varTag, 6},
{"x86HasFMA", varTag, 6}, {"x86HasFMA", varTag, 6},
@ -222,7 +220,7 @@ func params(tlist ...*types.Type) []*types.Field {
} }
func runtimeTypes() []*types.Type { func runtimeTypes() []*types.Type {
var typs [131]*types.Type var typs [136]*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[types.TANY] typs[2] = types.Types[types.TANY]
@ -281,78 +279,83 @@ func runtimeTypes() []*types.Type {
typs[55] = newSig(params(typs[28], typs[15]), params(typs[46], 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[56] = newSig(params(typs[28]), params(typs[15]))
typs[57] = newSig(params(typs[1], typs[2]), params(typs[2])) typs[57] = newSig(params(typs[1], typs[2]), params(typs[2]))
typs[58] = newSig(params(typs[2]), params(typs[7])) typs[58] = types.Types[types.TUINT16]
typs[59] = newSig(params(typs[1], typs[3]), params(typs[2])) typs[59] = newSig(params(typs[58]), params(typs[7]))
typs[60] = newSig(params(typs[1], typs[1]), params(typs[1])) typs[60] = types.Types[types.TUINT32]
typs[61] = newSig(params(typs[1], typs[1], typs[1]), nil) typs[61] = newSig(params(typs[60]), params(typs[7]))
typs[62] = newSig(params(typs[1]), nil) typs[62] = newSig(params(typs[24]), params(typs[7]))
typs[63] = types.NewPtr(typs[5]) typs[63] = newSig(params(typs[28]), params(typs[7]))
typs[64] = newSig(params(typs[63], typs[7], typs[7]), params(typs[6])) typs[64] = types.Types[types.TUINT8]
typs[65] = types.Types[types.TUINT32] typs[65] = types.NewSlice(typs[64])
typs[66] = newSig(nil, params(typs[65])) typs[66] = newSig(params(typs[65]), params(typs[7]))
typs[67] = types.NewMap(typs[2], typs[2]) typs[67] = newSig(params(typs[1], typs[3]), params(typs[2]))
typs[68] = newSig(params(typs[1], typs[22], typs[3]), params(typs[67])) typs[68] = newSig(params(typs[1], typs[1]), params(typs[1]))
typs[69] = newSig(params(typs[1], typs[15], typs[3]), params(typs[67])) typs[69] = newSig(params(typs[1], typs[1], typs[1]), nil)
typs[70] = newSig(nil, params(typs[67])) typs[70] = newSig(params(typs[1]), nil)
typs[71] = newSig(params(typs[1], typs[67], typs[3]), params(typs[3])) typs[71] = types.NewPtr(typs[5])
typs[72] = newSig(params(typs[1], typs[67], typs[2]), params(typs[3])) typs[72] = newSig(params(typs[71], typs[7], typs[7]), params(typs[6]))
typs[73] = newSig(params(typs[1], typs[67], typs[3], typs[1]), params(typs[3])) typs[73] = newSig(nil, params(typs[60]))
typs[74] = newSig(params(typs[1], typs[67], typs[3]), params(typs[3], typs[6])) typs[74] = types.NewMap(typs[2], typs[2])
typs[75] = newSig(params(typs[1], typs[67], typs[2]), params(typs[3], typs[6])) typs[75] = newSig(params(typs[1], typs[22], typs[3]), params(typs[74]))
typs[76] = newSig(params(typs[1], typs[67], typs[3], typs[1]), params(typs[3], typs[6])) typs[76] = newSig(params(typs[1], typs[15], typs[3]), params(typs[74]))
typs[77] = newSig(params(typs[1], typs[67], typs[3]), nil) typs[77] = newSig(nil, params(typs[74]))
typs[78] = newSig(params(typs[1], typs[67], typs[2]), nil) typs[78] = newSig(params(typs[1], typs[74], typs[3]), params(typs[3]))
typs[79] = newSig(params(typs[3]), nil) typs[79] = newSig(params(typs[1], typs[74], typs[2]), params(typs[3]))
typs[80] = newSig(params(typs[1], typs[67]), nil) typs[80] = newSig(params(typs[1], typs[74], typs[3], typs[1]), params(typs[3]))
typs[81] = types.NewChan(typs[2], types.Cboth) typs[81] = newSig(params(typs[1], typs[74], typs[3]), params(typs[3], typs[6]))
typs[82] = newSig(params(typs[1], typs[22]), params(typs[81])) typs[82] = newSig(params(typs[1], typs[74], typs[2]), params(typs[3], typs[6]))
typs[83] = newSig(params(typs[1], typs[15]), params(typs[81])) typs[83] = newSig(params(typs[1], typs[74], typs[3], typs[1]), params(typs[3], typs[6]))
typs[84] = types.NewChan(typs[2], types.Crecv) typs[84] = newSig(params(typs[1], typs[74], typs[3]), nil)
typs[85] = newSig(params(typs[84], typs[3]), nil) typs[85] = newSig(params(typs[1], typs[74], typs[2]), nil)
typs[86] = newSig(params(typs[84], typs[3]), params(typs[6])) typs[86] = newSig(params(typs[3]), nil)
typs[87] = types.NewChan(typs[2], types.Csend) typs[87] = newSig(params(typs[1], typs[74]), nil)
typs[88] = newSig(params(typs[87], typs[3]), nil) typs[88] = types.NewChan(typs[2], types.Cboth)
typs[89] = types.NewArray(typs[0], 3) typs[89] = newSig(params(typs[1], typs[22]), params(typs[88]))
typs[90] = types.NewStruct(types.NoPkg, []*types.Field{types.NewField(src.NoXPos, Lookup("enabled"), typs[6]), types.NewField(src.NoXPos, Lookup("pad"), typs[89]), types.NewField(src.NoXPos, Lookup("needed"), typs[6]), types.NewField(src.NoXPos, Lookup("cgo"), typs[6]), types.NewField(src.NoXPos, Lookup("alignme"), typs[24])}) typs[90] = newSig(params(typs[1], typs[15]), params(typs[88]))
typs[91] = newSig(params(typs[1], typs[3], typs[3]), nil) typs[91] = types.NewChan(typs[2], types.Crecv)
typs[92] = newSig(params(typs[1], typs[3]), nil) typs[92] = newSig(params(typs[91], typs[3]), nil)
typs[93] = newSig(params(typs[1], typs[3], typs[15], typs[3], typs[15]), params(typs[15])) typs[93] = newSig(params(typs[91], typs[3]), params(typs[6]))
typs[94] = newSig(params(typs[87], typs[3]), params(typs[6])) typs[94] = types.NewChan(typs[2], types.Csend)
typs[95] = newSig(params(typs[3], typs[84]), params(typs[6], typs[6])) typs[95] = newSig(params(typs[94], typs[3]), nil)
typs[96] = newSig(params(typs[63]), nil) typs[96] = types.NewArray(typs[0], 3)
typs[97] = newSig(params(typs[1], typs[1], typs[63], typs[15], typs[15], typs[6]), params(typs[15], typs[6])) typs[97] = types.NewStruct(types.NoPkg, []*types.Field{types.NewField(src.NoXPos, Lookup("enabled"), typs[6]), types.NewField(src.NoXPos, Lookup("pad"), typs[96]), types.NewField(src.NoXPos, Lookup("needed"), typs[6]), types.NewField(src.NoXPos, Lookup("cgo"), typs[6]), types.NewField(src.NoXPos, Lookup("alignme"), typs[24])})
typs[98] = newSig(params(typs[1], typs[15], typs[15]), params(typs[7])) typs[98] = newSig(params(typs[1], typs[3], typs[3]), nil)
typs[99] = newSig(params(typs[1], typs[22], typs[22]), params(typs[7])) typs[99] = newSig(params(typs[1], typs[3]), nil)
typs[100] = newSig(params(typs[1], typs[15], typs[15], typs[7]), params(typs[7])) typs[100] = newSig(params(typs[1], typs[3], typs[15], typs[3], typs[15]), params(typs[15]))
typs[101] = types.NewSlice(typs[2]) typs[101] = newSig(params(typs[94], typs[3]), params(typs[6]))
typs[102] = newSig(params(typs[1], typs[101], typs[15]), params(typs[101])) typs[102] = newSig(params(typs[3], typs[91]), params(typs[6], typs[6]))
typs[103] = newSig(params(typs[3], typs[3], typs[5]), nil) typs[103] = newSig(params(typs[71]), nil)
typs[104] = newSig(params(typs[7], typs[5]), nil) typs[104] = newSig(params(typs[1], typs[1], typs[71], typs[15], typs[15], typs[6]), params(typs[15], typs[6]))
typs[105] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6])) typs[105] = newSig(params(typs[1], typs[15], typs[15]), params(typs[7]))
typs[106] = newSig(params(typs[3], typs[3]), params(typs[6])) typs[106] = newSig(params(typs[1], typs[22], typs[22]), params(typs[7]))
typs[107] = newSig(params(typs[7], typs[7]), params(typs[6])) typs[107] = newSig(params(typs[1], typs[15], typs[15], typs[7]), params(typs[7]))
typs[108] = newSig(params(typs[7], typs[5], typs[5]), params(typs[5])) typs[108] = types.NewSlice(typs[2])
typs[109] = newSig(params(typs[7], typs[5]), params(typs[5])) typs[109] = newSig(params(typs[1], typs[108], typs[15]), params(typs[108]))
typs[110] = newSig(params(typs[22], typs[22]), params(typs[22])) typs[110] = newSig(params(typs[3], typs[3], typs[5]), nil)
typs[111] = newSig(params(typs[24], typs[24]), params(typs[24])) typs[111] = newSig(params(typs[7], typs[5]), nil)
typs[112] = newSig(params(typs[20]), params(typs[22])) typs[112] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6]))
typs[113] = newSig(params(typs[20]), params(typs[24])) typs[113] = newSig(params(typs[3], typs[3]), params(typs[6]))
typs[114] = newSig(params(typs[20]), params(typs[65])) typs[114] = newSig(params(typs[7], typs[7]), params(typs[6]))
typs[115] = newSig(params(typs[22]), params(typs[20])) typs[115] = newSig(params(typs[7], typs[5], typs[5]), params(typs[5]))
typs[116] = newSig(params(typs[24]), params(typs[20])) typs[116] = newSig(params(typs[7], typs[5]), params(typs[5]))
typs[117] = newSig(params(typs[65]), params(typs[20])) typs[117] = newSig(params(typs[22], typs[22]), params(typs[22]))
typs[118] = newSig(params(typs[26], typs[26]), params(typs[26])) typs[118] = newSig(params(typs[24], typs[24]), params(typs[24]))
typs[119] = newSig(nil, params(typs[5])) typs[119] = newSig(params(typs[20]), params(typs[22]))
typs[120] = newSig(params(typs[5], typs[5]), nil) typs[120] = newSig(params(typs[20]), params(typs[24]))
typs[121] = newSig(params(typs[5], typs[5], typs[5]), nil) typs[121] = newSig(params(typs[20]), params(typs[60]))
typs[122] = newSig(params(typs[7], typs[1], typs[5]), nil) typs[122] = newSig(params(typs[22]), params(typs[20]))
typs[123] = types.NewSlice(typs[7]) typs[123] = newSig(params(typs[24]), params(typs[20]))
typs[124] = newSig(params(typs[7], typs[123]), nil) typs[124] = newSig(params(typs[60]), params(typs[20]))
typs[125] = types.Types[types.TUINT8] typs[125] = newSig(params(typs[26], typs[26]), params(typs[26]))
typs[126] = newSig(params(typs[125], typs[125]), nil) typs[126] = newSig(nil, params(typs[5]))
typs[127] = types.Types[types.TUINT16] typs[127] = newSig(params(typs[5], typs[5]), nil)
typs[128] = newSig(params(typs[127], typs[127]), nil) typs[128] = newSig(params(typs[5], typs[5], typs[5]), nil)
typs[129] = newSig(params(typs[65], typs[65]), nil) typs[129] = newSig(params(typs[7], typs[1], typs[5]), nil)
typs[130] = newSig(params(typs[24], typs[24]), nil) typs[130] = types.NewSlice(typs[7])
typs[131] = newSig(params(typs[7], typs[130]), nil)
typs[132] = newSig(params(typs[64], typs[64]), nil)
typs[133] = newSig(params(typs[58], typs[58]), nil)
typs[134] = newSig(params(typs[60], typs[60]), nil)
typs[135] = newSig(params(typs[24], typs[24]), nil)
return typs[:] return typs[:]
} }

View File

@ -87,13 +87,16 @@ func convI2I(typ *byte, elem any) (ret any)
// Specialized type-to-interface conversion. // Specialized type-to-interface conversion.
// These return only a data pointer. // These return only a data pointer.
func convT16(val any) unsafe.Pointer // val must be uint16-like (same size and alignment as a uint16) // These functions take concrete types in the runtime. But they may
func convT32(val any) unsafe.Pointer // val must be uint32-like (same size and alignment as a uint32) // be used for a wider range of types, which have the same memory
func convT32F(val any) unsafe.Pointer // val must be float32-like // layout as the parameter type. The compiler converts the
func convT64(val any) unsafe.Pointer // val must be uint64-like (same size and alignment as a uint64 and contains no pointers) // to-be-converted type to the parameter type before calling the
func convT64F(val any) unsafe.Pointer // val must be float64-like // runtime function. This way, the call is ABI-insensitive.
func convTstring(val any) unsafe.Pointer // val must be a string func convT16(val uint16) unsafe.Pointer
func convTslice(val any) unsafe.Pointer // val must be a slice func convT32(val uint32) unsafe.Pointer
func convT64(val uint64) unsafe.Pointer
func convTstring(val string) unsafe.Pointer
func convTslice(val []uint8) unsafe.Pointer
// Type to empty-interface conversion. // Type to empty-interface conversion.
func convT2E(typ *byte, elem *any) (ret any) func convT2E(typ *byte, elem *any) (ret any)

View File

@ -14,7 +14,6 @@ import (
"cmd/compile/internal/ssagen" "cmd/compile/internal/ssagen"
"cmd/compile/internal/typecheck" "cmd/compile/internal/typecheck"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/objabi"
"cmd/internal/sys" "cmd/internal/sys"
) )
@ -136,7 +135,7 @@ func walkConvInterface(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
return e return e
} }
fnname, needsaddr := convFuncName(fromType, toType) fnname, argType, needsaddr := convFuncName(fromType, toType)
if !needsaddr && !fromType.IsInterface() { if !needsaddr && !fromType.IsInterface() {
// Use a specialized conversion routine that only returns a data pointer. // Use a specialized conversion routine that only returns a data pointer.
@ -144,10 +143,29 @@ func walkConvInterface(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
// e = iface{typ/tab, ptr} // e = iface{typ/tab, ptr}
fn := typecheck.LookupRuntime(fnname) fn := typecheck.LookupRuntime(fnname)
types.CalcSize(fromType) types.CalcSize(fromType)
fn = typecheck.SubstArgTypes(fn, fromType)
types.CalcSize(fn.Type()) arg := n.X
switch {
case fromType == argType:
// already in the right type, nothing to do
case fromType.Kind() == argType.Kind(),
fromType.IsPtrShaped() && argType.IsPtrShaped():
// can directly convert (e.g. named type to underlying type, or one pointer to another)
arg = ir.NewConvExpr(n.Pos(), ir.OCONVNOP, argType, arg)
case fromType.IsInteger() && argType.IsInteger():
// can directly convert (e.g. int32 to uint32)
arg = ir.NewConvExpr(n.Pos(), ir.OCONV, argType, arg)
default:
// unsafe cast through memory
arg = copyExpr(arg, arg.Type(), init)
var addr ir.Node = typecheck.NodAddr(arg)
addr = ir.NewConvExpr(n.Pos(), ir.OCONVNOP, argType.PtrTo(), addr)
arg = ir.NewStarExpr(n.Pos(), addr)
arg.SetType(argType)
}
call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil) call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
call.Args = []ir.Node{n.X} call.Args = []ir.Node{arg}
e := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeword(), safeExpr(walkExpr(typecheck.Expr(call), init), init)) e := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeword(), safeExpr(walkExpr(typecheck.Expr(call), init), init))
e.SetType(toType) e.SetType(toType)
e.SetTypecheck(1) e.SetTypecheck(1)
@ -295,77 +313,45 @@ func walkStringToRunes(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
} }
// convFuncName builds the runtime function name for interface conversion. // convFuncName builds the runtime function name for interface conversion.
// It also reports whether the function expects the data by address. // It also returns the argument type that the runtime function takes, and
// whether the function expects the data by address.
// Not all names are possible. For example, we never generate convE2E or convE2I. // Not all names are possible. For example, we never generate convE2E or convE2I.
func convFuncName(from, to *types.Type) (fnname string, needsaddr bool) { func convFuncName(from, to *types.Type) (fnname string, argType *types.Type, needsaddr bool) {
// With register-based ABI, float32 and uint32 are passed in different
// registers, so we cannot use convT32 for float32.
// isFloatLike returns whether t is a float-like type (float32, float64,
// single-element array/struct with a float-like element), for which
// the argument is passed in a floating point register under register-
// based ABI.
var isFloatLike func(t *types.Type) bool
isFloatLike = func(t *types.Type) bool {
switch t.Kind() {
case types.TFLOAT32, types.TFLOAT64:
return true
case types.TARRAY:
return t.NumElem() == 1 && isFloatLike(t.Elem())
case types.TSTRUCT:
fsl := t.FieldSlice()
for idx, f := range fsl {
if f.Type.Width == 0 {
continue
}
if isFloatLike(f.Type) && idx == len(fsl)-1 {
return true
}
return false
}
return false
}
return false
}
tkind := to.Tie() tkind := to.Tie()
switch from.Tie() { switch from.Tie() {
case 'I': case 'I':
if tkind == 'I' { if tkind == 'I' {
return "convI2I", false return "convI2I", types.Types[types.TINTER], false
} }
case 'T': case 'T':
switch { switch {
case from.Size() == 2 && from.Align == 2: case from.Size() == 2 && from.Align == 2:
return "convT16", false return "convT16", types.Types[types.TUINT16], false
case from.Size() == 4 && isFloatLike(from): case from.Size() == 4 && from.Align == 4 && !from.HasPointers():
return "convT32F", false return "convT32", types.Types[types.TUINT32], false
case from.Size() == 4 && from.Align == 4 && !from.HasPointers() && (!objabi.Experiment.RegabiArgs || from.NumComponents(types.CountBlankFields) == 1): case from.Size() == 8 && from.Align == types.Types[types.TUINT64].Align && !from.HasPointers():
return "convT32", false return "convT64", types.Types[types.TUINT64], false
case from.Size() == 8 && isFloatLike(from):
return "convT64F", false
case from.Size() == 8 && from.Align == types.Types[types.TUINT64].Align && !from.HasPointers() && (!objabi.Experiment.RegabiArgs || from.NumComponents(types.CountBlankFields) == 1):
return "convT64", false
} }
if sc := from.SoleComponent(); sc != nil { if sc := from.SoleComponent(); sc != nil {
switch { switch {
case sc.IsString(): case sc.IsString():
return "convTstring", false return "convTstring", types.Types[types.TSTRING], false
case sc.IsSlice(): case sc.IsSlice():
return "convTslice", false return "convTslice", types.NewSlice(types.Types[types.TUINT8]), false // the element type doesn't matter
} }
} }
switch tkind { switch tkind {
case 'E': case 'E':
if !from.HasPointers() { if !from.HasPointers() {
return "convT2Enoptr", true return "convT2Enoptr", types.Types[types.TUNSAFEPTR], true
} }
return "convT2E", true return "convT2E", types.Types[types.TUNSAFEPTR], true
case 'I': case 'I':
if !from.HasPointers() { if !from.HasPointers() {
return "convT2Inoptr", true return "convT2Inoptr", types.Types[types.TUNSAFEPTR], true
} }
return "convT2I", true return "convT2I", types.Types[types.TUNSAFEPTR], true
} }
} }
base.Fatalf("unknown conv func %c2%c", from.Tie(), to.Tie()) base.Fatalf("unknown conv func %c2%c", from.Tie(), to.Tie())

View File

@ -1147,7 +1147,7 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node {
if n.X.Type().IsInterface() { if n.X.Type().IsInterface() {
return n return n
} }
if _, needsaddr := convFuncName(n.X.Type(), n.Type()); needsaddr || isStaticCompositeLiteral(n.X) { if _, _, needsaddr := convFuncName(n.X.Type(), n.Type()); needsaddr || isStaticCompositeLiteral(n.X) {
// Need a temp if we need to pass the address to the conversion function. // Need a temp if we need to pass the address to the conversion function.
// We also process static composite literal node here, making a named static global // We also process static composite literal node here, making a named static global
// whose address we can put directly in an interface (see OCONVIFACE case in walk). // whose address we can put directly in an interface (see OCONVIFACE case in walk).

View File

@ -357,10 +357,6 @@ func convT32(val uint32) (x unsafe.Pointer) {
return return
} }
func convT32F(val float32) (x unsafe.Pointer) {
return convT32(*(*uint32)(unsafe.Pointer(&val)))
}
func convT64(val uint64) (x unsafe.Pointer) { func convT64(val uint64) (x unsafe.Pointer) {
if val < uint64(len(staticuint64s)) { if val < uint64(len(staticuint64s)) {
x = unsafe.Pointer(&staticuint64s[val]) x = unsafe.Pointer(&staticuint64s[val])
@ -371,10 +367,6 @@ func convT64(val uint64) (x unsafe.Pointer) {
return return
} }
func convT64F(val float64) (x unsafe.Pointer) {
return convT64(*(*uint64)(unsafe.Pointer(&val)))
}
func convTstring(val string) (x unsafe.Pointer) { func convTstring(val string) (x unsafe.Pointer) {
if val == "" { if val == "" {
x = unsafe.Pointer(&zeroVal[0]) x = unsafe.Pointer(&zeroVal[0])