diff --git a/src/cmd/compile/internal/typecheck/builtin.go b/src/cmd/compile/internal/typecheck/builtin.go index 3421c445888..225dd682f03 100644 --- a/src/cmd/compile/internal/typecheck/builtin.go +++ b/src/cmd/compile/internal/typecheck/builtin.go @@ -73,7 +73,9 @@ var runtimeDecls = [...]struct { {"convI2I", funcTag, 57}, {"convT16", funcTag, 58}, {"convT32", funcTag, 58}, + {"convT32F", funcTag, 58}, {"convT64", funcTag, 58}, + {"convT64F", funcTag, 58}, {"convTstring", funcTag, 58}, {"convTslice", funcTag, 58}, {"convT2E", funcTag, 59}, diff --git a/src/cmd/compile/internal/typecheck/builtin/runtime.go b/src/cmd/compile/internal/typecheck/builtin/runtime.go index 614bd46177f..7c9599b54e8 100644 --- a/src/cmd/compile/internal/typecheck/builtin/runtime.go +++ b/src/cmd/compile/internal/typecheck/builtin/runtime.go @@ -89,7 +89,9 @@ func convI2I(typ *byte, elem any) (ret any) // These return only a data pointer. func convT16(val any) unsafe.Pointer // val must be uint16-like (same size and alignment as a uint16) func convT32(val any) unsafe.Pointer // val must be uint32-like (same size and alignment as a uint32) +func convT32F(val any) unsafe.Pointer // val must be float32-like func convT64(val any) unsafe.Pointer // val must be uint64-like (same size and alignment as a uint64 and contains no pointers) +func convT64F(val any) unsafe.Pointer // val must be float64-like func convTstring(val any) unsafe.Pointer // val must be a string func convTslice(val any) unsafe.Pointer // val must be a slice diff --git a/src/cmd/compile/internal/walk/convert.go b/src/cmd/compile/internal/walk/convert.go index fa8e2c0bb8d..168f42ee485 100644 --- a/src/cmd/compile/internal/walk/convert.go +++ b/src/cmd/compile/internal/walk/convert.go @@ -297,6 +297,25 @@ func walkStringToRunes(n *ir.ConvExpr, init *ir.Nodes) ir.Node { // It also reports whether the function expects the data by address. // Not all names are possible. For example, we never generate convE2E or convE2I. func convFuncName(from, to *types.Type) (fnname string, 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: + return t.NumFields() == 1 && isFloatLike(t.Field(0).Type) + } + return false + } + tkind := to.Tie() switch from.Tie() { case 'I': @@ -307,8 +326,12 @@ func convFuncName(from, to *types.Type) (fnname string, needsaddr bool) { switch { case from.Size() == 2 && from.Align == 2: return "convT16", false + case from.Size() == 4 && isFloatLike(from): + return "convT32F", false case from.Size() == 4 && from.Align == 4 && !from.HasPointers(): return "convT32", false + case from.Size() == 8 && isFloatLike(from): + return "convT64F", false case from.Size() == 8 && from.Align == types.Types[types.TUINT64].Align && !from.HasPointers(): return "convT64", false } diff --git a/src/runtime/iface.go b/src/runtime/iface.go index cd5fead9990..f5ac627d39a 100644 --- a/src/runtime/iface.go +++ b/src/runtime/iface.go @@ -357,6 +357,10 @@ func convT32(val uint32) (x unsafe.Pointer) { return } +func convT32F(val float32) (x unsafe.Pointer) { + return convT32(*(*uint32)(unsafe.Pointer(&val))) +} + func convT64(val uint64) (x unsafe.Pointer) { if val < uint64(len(staticuint64s)) { x = unsafe.Pointer(&staticuint64s[val]) @@ -367,6 +371,10 @@ func convT64(val uint64) (x unsafe.Pointer) { return } +func convT64F(val float64) (x unsafe.Pointer) { + return convT64(*(*uint64)(unsafe.Pointer(&val))) +} + func convTstring(val string) (x unsafe.Pointer) { if val == "" { x = unsafe.Pointer(&zeroVal[0])