]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: handle sole component for 1-byte type interface conversion
authorCuong Manh Le <cuong.manhle.vn@gmail.com>
Tue, 30 Nov 2021 17:28:25 +0000 (00:28 +0700)
committerCuong Manh Le <cuong.manhle.vn@gmail.com>
Fri, 25 Mar 2022 15:15:57 +0000 (15:15 +0000)
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 <cuong.manhle.vn@gmail.com>
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/cmd/compile/internal/types/type.go
src/cmd/compile/internal/walk/convert.go

index 098ce385c47b9077b0ff015afa3bef6cf513443e..c8d11b5bb92f2bae0d4ffc2885c8bfa9882bb8a7 100644 (file)
@@ -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:
index ffc5fd19e801dcfbc2bdd046bc43eb3fda9104c7..6edff4fbba607d3f59a86a2db997400d7021f9e0 100644 (file)
@@ -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.