Skip to content

Commit

Permalink
cmd/compile: handle sole component for 1-byte type interface conversion
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Keith Randall <[email protected]>
Run-TryBot: Cuong Manh Le <[email protected]>
TryBot-Result: Gopher Robot <[email protected]>
  • Loading branch information
cuonglm committed Mar 25, 2022
1 parent 8ab42a9 commit 3fd8b86
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/cmd/compile/internal/types/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
32 changes: 31 additions & 1 deletion src/cmd/compile/internal/walk/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,17 +118,24 @@ 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 {
case fromType.Size() == 0:
// 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 {
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit 3fd8b86

Please sign in to comment.