From 3fd8b8627f39d34e1a66bf4d610784bcd3f4319d Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Wed, 1 Dec 2021 00:28:25 +0700 Subject: [PATCH] cmd/compile: handle sole component for 1-byte type interface conversion For 1-byte type, we have a special case for converting to interface type. But we missed an optimization for sole component-ed types, this CL add that one. goos: linux goarch: amd64 cpu: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz Benchmark_BoolField-8 1000000000 0.6473 ns/op Benchmark_ByteField-8 1000000000 0.6094 ns/op Benchmark_Uint8Field-8 1000000000 0.6385 ns/op Benchmark_Int16Field-8 785179434 1.481 ns/op Benchmark_Int32Field-8 796127782 1.539 ns/op Benchmark_Int64Field-8 718815478 1.657 ns/op Fixes #49879 Change-Id: Idc0e9d3ff738c8c8081b8e8d65093dacf2bcf392 Reviewed-on: https://go-review.googlesource.com/c/go/+/367755 Trust: Cuong Manh Le Reviewed-by: Keith Randall Run-TryBot: Cuong Manh Le TryBot-Result: Gopher Robot --- src/cmd/compile/internal/types/type.go | 1 + src/cmd/compile/internal/walk/convert.go | 32 +++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index 098ce385c4..c8d11b5bb9 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -1628,6 +1628,7 @@ func (t *Type) NumComponents(countBlank componentsIncludeBlankFields) int64 { // SoleComponent returns the only primitive component in t, // if there is exactly one. Otherwise, it returns nil. // Components are counted as in NumComponents, including blank fields. +// Keep in sync with cmd/compile/internal/walk/convert.go:soleComponent. func (t *Type) SoleComponent() *Type { switch t.kind { case TSTRUCT: diff --git a/src/cmd/compile/internal/walk/convert.go b/src/cmd/compile/internal/walk/convert.go index ffc5fd19e8..6edff4fbba 100644 --- a/src/cmd/compile/internal/walk/convert.go +++ b/src/cmd/compile/internal/walk/convert.go @@ -118,6 +118,12 @@ func dataWord(pos src.XPos, n ir.Node, init *ir.Nodes, escapes bool) ir.Node { return n } + isInteger := fromType.IsInteger() + isBool := fromType.IsBoolean() + if sc := fromType.SoleComponent(); sc != nil { + isInteger = sc.IsInteger() + isBool = sc.IsBoolean() + } // Try a bunch of cases to avoid an allocation. var value ir.Node switch { @@ -125,10 +131,11 @@ func dataWord(pos src.XPos, n ir.Node, init *ir.Nodes, escapes bool) ir.Node { // n is zero-sized. Use zerobase. cheapExpr(n, init) // Evaluate n for side-effects. See issue 19246. value = ir.NewLinksymExpr(base.Pos, ir.Syms.Zerobase, types.Types[types.TUINTPTR]) - case fromType.IsBoolean() || (fromType.Size() == 1 && fromType.IsInteger()): + case isBool || fromType.Size() == 1 && isInteger: // n is a bool/byte. Use staticuint64s[n * 8] on little-endian // and staticuint64s[n * 8 + 7] on big-endian. n = cheapExpr(n, init) + n = soleComponent(init, n) // byteindex widens n so that the multiplication doesn't overflow. index := ir.NewBinaryExpr(base.Pos, ir.OLSH, byteindex(n), ir.NewInt(3)) if ssagen.Arch.LinkArch.ByteOrder == binary.BigEndian { @@ -392,6 +399,29 @@ func rtconvfn(src, dst *types.Type) (param, result types.Kind) { return types.Txxx, types.Txxx } +func soleComponent(init *ir.Nodes, n ir.Node) ir.Node { + if n.Type().SoleComponent() == nil { + return n + } + // Keep in sync with cmd/compile/internal/types/type.go:Type.SoleComponent. + for { + switch { + case n.Type().IsStruct(): + if n.Type().Field(0).Sym.IsBlank() { + // Treat blank fields as the zero value as the Go language requires. + n = typecheck.Temp(n.Type().Field(0).Type) + appendWalkStmt(init, ir.NewAssignStmt(base.Pos, n, nil)) + return n + } + n = typecheck.Expr(ir.NewSelectorExpr(n.Pos(), ir.OXDOT, n, n.Type().Field(0).Sym)) + case n.Type().IsArray(): + n = typecheck.Expr(ir.NewIndexExpr(n.Pos(), n, ir.NewInt(0))) + default: + return n + } + } +} + // byteindex converts n, which is byte-sized, to an int used to index into an array. // We cannot use conv, because we allow converting bool to int here, // which is forbidden in user code. -- 2.48.1